1 use actix_web::{guard, web, Error, HttpResponse, Result};
2 use lemmy_api::Perform;
3 use lemmy_api_common::{
32 context::LemmyContext,
33 custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji},
49 MarkCommentReplyAsRead,
50 MarkPersonMentionAsRead,
51 PasswordChangeAfterReset,
76 CreatePrivateMessageReport,
80 ListPrivateMessageReports,
81 MarkPrivateMessageAsRead,
82 ResolvePrivateMessageReport,
85 ApproveRegistrationApplication,
88 GetFederatedInstances,
91 GetUnreadRegistrationApplicationCount,
93 ListRegistrationApplications,
101 websocket::structs::{CommunityJoin, ModJoin, PostJoin, UserJoin},
103 use lemmy_api_crud::PerformCrud;
104 use lemmy_apub::{api::PerformApub, SendActivity};
105 use lemmy_utils::rate_limit::RateLimitCell;
106 use serde::Deserialize;
108 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
110 web::scope("/api/v3")
114 .wrap(rate_limit.message())
115 .route("", web::get().to(route_get_crud::<GetSite>))
117 .route("", web::post().to(route_post_crud::<CreateSite>))
118 .route("", web::put().to(route_post_crud::<EditSite>)),
121 web::resource("/modlog")
122 .wrap(rate_limit.message())
123 .route(web::get().to(route_get::<GetModlog>)),
126 web::resource("/search")
127 .wrap(rate_limit.search())
128 .route(web::get().to(route_get_apub::<Search>)),
131 web::resource("/resolve_object")
132 .wrap(rate_limit.message())
133 .route(web::get().to(route_get_apub::<ResolveObject>)),
137 web::resource("/community")
138 .guard(guard::Post())
139 .wrap(rate_limit.register())
140 .route(web::post().to(route_post_crud::<CreateCommunity>)),
143 web::scope("/community")
144 .wrap(rate_limit.message())
145 .route("", web::get().to(route_get_apub::<GetCommunity>))
146 .route("", web::put().to(route_post_crud::<EditCommunity>))
147 .route("/hide", web::put().to(route_post::<HideCommunity>))
148 .route("/list", web::get().to(route_get_crud::<ListCommunities>))
149 .route("/follow", web::post().to(route_post::<FollowCommunity>))
150 .route("/block", web::post().to(route_post::<BlockCommunity>))
153 web::post().to(route_post_crud::<DeleteCommunity>),
158 web::post().to(route_post_crud::<RemoveCommunity>),
160 .route("/transfer", web::post().to(route_post::<TransferCommunity>))
161 .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
162 .route("/mod", web::post().to(route_post::<AddModToCommunity>))
163 .route("/join", web::post().to(route_post::<CommunityJoin>))
164 .route("/mod/join", web::post().to(route_post::<ModJoin>)),
167 web::scope("/federated_instances")
168 .wrap(rate_limit.message())
169 .route("", web::get().to(route_get::<GetFederatedInstances>)),
173 // Handle POST to /post separately to add the post() rate limitter
174 web::resource("/post")
175 .guard(guard::Post())
176 .wrap(rate_limit.post())
177 .route(web::post().to(route_post_crud::<CreatePost>)),
181 .wrap(rate_limit.message())
182 .route("", web::get().to(route_get_crud::<GetPost>))
183 .route("", web::put().to(route_post_crud::<EditPost>))
184 .route("/delete", web::post().to(route_post_crud::<DeletePost>))
185 .route("/remove", web::post().to(route_post_crud::<RemovePost>))
188 web::post().to(route_post::<MarkPostAsRead>),
190 .route("/lock", web::post().to(route_post::<LockPost>))
191 .route("/feature", web::post().to(route_post::<FeaturePost>))
192 .route("/list", web::get().to(route_get_apub::<GetPosts>))
193 .route("/like", web::post().to(route_post::<CreatePostLike>))
194 .route("/save", web::put().to(route_post::<SavePost>))
195 .route("/join", web::post().to(route_post::<PostJoin>))
196 .route("/report", web::post().to(route_post::<CreatePostReport>))
199 web::put().to(route_post::<ResolvePostReport>),
201 .route("/report/list", web::get().to(route_get::<ListPostReports>))
204 web::get().to(route_get::<GetSiteMetadata>),
209 // Handle POST to /comment separately to add the comment() rate limitter
210 web::resource("/comment")
211 .guard(guard::Post())
212 .wrap(rate_limit.comment())
213 .route(web::post().to(route_post_crud::<CreateComment>)),
216 web::scope("/comment")
217 .wrap(rate_limit.message())
218 .route("", web::get().to(route_get_crud::<GetComment>))
219 .route("", web::put().to(route_post_crud::<EditComment>))
220 .route("/delete", web::post().to(route_post_crud::<DeleteComment>))
221 .route("/remove", web::post().to(route_post_crud::<RemoveComment>))
224 web::post().to(route_post::<MarkCommentReplyAsRead>),
228 web::post().to(route_post::<DistinguishComment>),
230 .route("/like", web::post().to(route_post::<CreateCommentLike>))
231 .route("/save", web::put().to(route_post::<SaveComment>))
232 .route("/list", web::get().to(route_get_apub::<GetComments>))
233 .route("/report", web::post().to(route_post::<CreateCommentReport>))
236 web::put().to(route_post::<ResolveCommentReport>),
240 web::get().to(route_get::<ListCommentReports>),
245 web::scope("/private_message")
246 .wrap(rate_limit.message())
247 .route("/list", web::get().to(route_get_crud::<GetPrivateMessages>))
248 .route("", web::post().to(route_post_crud::<CreatePrivateMessage>))
249 .route("", web::put().to(route_post_crud::<EditPrivateMessage>))
252 web::post().to(route_post_crud::<DeletePrivateMessage>),
256 web::post().to(route_post::<MarkPrivateMessageAsRead>),
260 web::post().to(route_post::<CreatePrivateMessageReport>),
264 web::put().to(route_post::<ResolvePrivateMessageReport>),
268 web::get().to(route_get::<ListPrivateMessageReports>),
273 // Account action, I don't like that it's in /user maybe /accounts
274 // Handle /user/register separately to add the register() rate limitter
275 web::resource("/user/register")
276 .guard(guard::Post())
277 .wrap(rate_limit.register())
278 .route(web::post().to(route_post_crud::<Register>)),
281 // Handle captcha separately
282 web::resource("/user/get_captcha")
283 .wrap(rate_limit.post())
284 .route(web::get().to(route_get::<GetCaptcha>)),
289 .wrap(rate_limit.message())
290 .route("", web::get().to(route_get_apub::<GetPersonDetails>))
291 .route("/mention", web::get().to(route_get::<GetPersonMentions>))
293 "/mention/mark_as_read",
294 web::post().to(route_post::<MarkPersonMentionAsRead>),
296 .route("/replies", web::get().to(route_get::<GetReplies>))
297 .route("/join", web::post().to(route_post::<UserJoin>))
298 // Admin action. I don't like that it's in /user
299 .route("/ban", web::post().to(route_post::<BanPerson>))
300 .route("/banned", web::get().to(route_get::<GetBannedPersons>))
301 .route("/block", web::post().to(route_post::<BlockPerson>))
302 // Account actions. I don't like that they're in /user maybe /accounts
303 .route("/login", web::post().to(route_post::<Login>))
306 web::post().to(route_post_crud::<DeleteAccount>),
310 web::post().to(route_post::<PasswordReset>),
314 web::post().to(route_post::<PasswordChangeAfterReset>),
316 // mark_all_as_read feels off being in this section as well
319 web::post().to(route_post::<MarkAllAsRead>),
322 "/save_user_settings",
323 web::put().to(route_post::<SaveUserSettings>),
327 web::put().to(route_post::<ChangePassword>),
329 .route("/report_count", web::get().to(route_get::<GetReportCount>))
330 .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
331 .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
332 .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
337 .wrap(rate_limit.message())
338 .route("/add", web::post().to(route_post::<AddAdmin>))
340 "/registration_application/count",
341 web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
344 "/registration_application/list",
345 web::get().to(route_get::<ListRegistrationApplications>),
348 "/registration_application/approve",
349 web::put().to(route_post::<ApproveRegistrationApplication>),
353 web::scope("/admin/purge")
354 .wrap(rate_limit.message())
355 .route("/person", web::post().to(route_post::<PurgePerson>))
356 .route("/community", web::post().to(route_post::<PurgeCommunity>))
357 .route("/post", web::post().to(route_post::<PurgePost>))
358 .route("/comment", web::post().to(route_post::<PurgeComment>)),
361 web::scope("/custom_emoji")
362 .wrap(rate_limit.message())
363 .route("", web::post().to(route_post_crud::<CreateCustomEmoji>))
364 .route("", web::put().to(route_post_crud::<EditCustomEmoji>))
367 web::post().to(route_post_crud::<DeleteCustomEmoji>),
373 async fn perform<'a, Data>(
375 context: web::Data<LemmyContext>,
376 apub_data: activitypub_federation::config::Data<LemmyContext>,
377 ) -> Result<HttpResponse, Error>
380 + SendActivity<Response = <Data as Perform>::Response>
386 let res = data.perform(&context, None).await?;
387 SendActivity::send_activity(&data, &res, &apub_data).await?;
388 Ok(HttpResponse::Ok().json(res))
391 async fn route_get<'a, Data>(
392 data: web::Query<Data>,
393 context: web::Data<LemmyContext>,
394 apub_data: activitypub_federation::config::Data<LemmyContext>,
395 ) -> Result<HttpResponse, Error>
398 + SendActivity<Response = <Data as Perform>::Response>
404 perform::<Data>(data.0, context, apub_data).await
407 async fn route_get_apub<'a, Data>(
408 data: web::Query<Data>,
409 context: activitypub_federation::config::Data<LemmyContext>,
410 ) -> Result<HttpResponse, Error>
413 + SendActivity<Response = <Data as PerformApub>::Response>
419 let res = data.perform(&context, None).await?;
420 SendActivity::send_activity(&data.0, &res, &context).await?;
421 Ok(HttpResponse::Ok().json(res))
424 async fn route_post<'a, Data>(
425 data: web::Json<Data>,
426 context: web::Data<LemmyContext>,
427 apub_data: activitypub_federation::config::Data<LemmyContext>,
428 ) -> Result<HttpResponse, Error>
431 + SendActivity<Response = <Data as Perform>::Response>
437 perform::<Data>(data.0, context, apub_data).await
440 async fn perform_crud<'a, Data>(
442 context: web::Data<LemmyContext>,
443 apub_data: activitypub_federation::config::Data<LemmyContext>,
444 ) -> Result<HttpResponse, Error>
447 + SendActivity<Response = <Data as PerformCrud>::Response>
453 let res = data.perform(&context, None).await?;
454 SendActivity::send_activity(&data, &res, &apub_data).await?;
455 Ok(HttpResponse::Ok().json(res))
458 async fn route_get_crud<'a, Data>(
459 data: web::Query<Data>,
460 context: web::Data<LemmyContext>,
461 apub_data: activitypub_federation::config::Data<LemmyContext>,
462 ) -> Result<HttpResponse, Error>
465 + SendActivity<Response = <Data as PerformCrud>::Response>
471 perform_crud::<Data>(data.0, context, apub_data).await
474 async fn route_post_crud<'a, Data>(
475 data: web::Json<Data>,
476 context: web::Data<LemmyContext>,
477 apub_data: activitypub_federation::config::Data<LemmyContext>,
478 ) -> Result<HttpResponse, Error>
481 + SendActivity<Response = <Data as PerformCrud>::Response>
487 perform_crud::<Data>(data.0, context, apub_data).await