1 use actix_web::{guard, web, Error, HttpResponse, Result};
2 use lemmy_api::Perform;
3 use lemmy_api_common::{
30 context::LemmyContext,
31 custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji},
46 MarkCommentReplyAsRead,
47 MarkPersonMentionAsRead,
48 PasswordChangeAfterReset,
71 CreatePrivateMessageReport,
75 ListPrivateMessageReports,
76 MarkPrivateMessageAsRead,
77 ResolvePrivateMessageReport,
80 ApproveRegistrationApplication,
83 GetFederatedInstances,
86 GetUnreadRegistrationApplicationCount,
88 ListRegistrationApplications,
95 use lemmy_api_crud::{post::create::create_post, PerformCrud};
98 list_comments::list_comments,
99 list_posts::list_posts,
100 read_community::read_community,
101 read_person::read_person,
102 resolve_object::resolve_object,
107 use lemmy_utils::{rate_limit::RateLimitCell, spawn_try_task, SYNCHRONOUS_FEDERATION};
108 use serde::Deserialize;
110 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
112 web::scope("/api/v3")
116 .wrap(rate_limit.message())
117 .route("", web::get().to(route_get_crud::<GetSite>))
119 .route("", web::post().to(route_post_crud::<CreateSite>))
120 .route("", web::put().to(route_post_crud::<EditSite>)),
123 web::resource("/modlog")
124 .wrap(rate_limit.message())
125 .route(web::get().to(route_get::<GetModlog>)),
128 web::resource("/search")
129 .wrap(rate_limit.search())
130 .route(web::get().to(search)),
133 web::resource("/resolve_object")
134 .wrap(rate_limit.message())
135 .route(web::get().to(resolve_object)),
139 web::resource("/community")
140 .guard(guard::Post())
141 .wrap(rate_limit.register())
142 .route(web::post().to(route_post_crud::<CreateCommunity>)),
145 web::scope("/community")
146 .wrap(rate_limit.message())
147 .route("", web::get().to(read_community))
148 .route("", web::put().to(route_post_crud::<EditCommunity>))
149 .route("/hide", web::put().to(route_post::<HideCommunity>))
150 .route("/list", web::get().to(route_get_crud::<ListCommunities>))
151 .route("/follow", web::post().to(route_post::<FollowCommunity>))
152 .route("/block", web::post().to(route_post::<BlockCommunity>))
155 web::post().to(route_post_crud::<DeleteCommunity>),
160 web::post().to(route_post_crud::<RemoveCommunity>),
162 .route("/transfer", web::post().to(route_post::<TransferCommunity>))
163 .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
164 .route("/mod", web::post().to(route_post::<AddModToCommunity>)),
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(create_post)),
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(list_posts))
193 .route("/like", web::post().to(route_post::<CreatePostLike>))
194 .route("/save", web::put().to(route_post::<SavePost>))
195 .route("/report", web::post().to(route_post::<CreatePostReport>))
198 web::put().to(route_post::<ResolvePostReport>),
200 .route("/report/list", web::get().to(route_get::<ListPostReports>))
203 web::get().to(route_get::<GetSiteMetadata>),
208 // Handle POST to /comment separately to add the comment() rate limitter
209 web::resource("/comment")
210 .guard(guard::Post())
211 .wrap(rate_limit.comment())
212 .route(web::post().to(route_post_crud::<CreateComment>)),
215 web::scope("/comment")
216 .wrap(rate_limit.message())
217 .route("", web::get().to(route_get_crud::<GetComment>))
218 .route("", web::put().to(route_post_crud::<EditComment>))
219 .route("/delete", web::post().to(route_post_crud::<DeleteComment>))
220 .route("/remove", web::post().to(route_post_crud::<RemoveComment>))
223 web::post().to(route_post::<MarkCommentReplyAsRead>),
227 web::post().to(route_post::<DistinguishComment>),
229 .route("/like", web::post().to(route_post::<CreateCommentLike>))
230 .route("/save", web::put().to(route_post::<SaveComment>))
231 .route("/list", web::get().to(list_comments))
232 .route("/report", web::post().to(route_post::<CreateCommentReport>))
235 web::put().to(route_post::<ResolveCommentReport>),
239 web::get().to(route_get::<ListCommentReports>),
244 web::scope("/private_message")
245 .wrap(rate_limit.message())
246 .route("/list", web::get().to(route_get_crud::<GetPrivateMessages>))
247 .route("", web::post().to(route_post_crud::<CreatePrivateMessage>))
248 .route("", web::put().to(route_post_crud::<EditPrivateMessage>))
251 web::post().to(route_post_crud::<DeletePrivateMessage>),
255 web::post().to(route_post::<MarkPrivateMessageAsRead>),
259 web::post().to(route_post::<CreatePrivateMessageReport>),
263 web::put().to(route_post::<ResolvePrivateMessageReport>),
267 web::get().to(route_get::<ListPrivateMessageReports>),
272 // Account action, I don't like that it's in /user maybe /accounts
273 // Handle /user/register separately to add the register() rate limitter
274 web::resource("/user/register")
275 .guard(guard::Post())
276 .wrap(rate_limit.register())
277 .route(web::post().to(route_post_crud::<Register>)),
280 // Handle captcha separately
281 web::resource("/user/get_captcha")
282 .wrap(rate_limit.post())
283 .route(web::get().to(route_get::<GetCaptcha>)),
288 .wrap(rate_limit.message())
289 .route("", web::get().to(read_person))
290 .route("/mention", web::get().to(route_get::<GetPersonMentions>))
292 "/mention/mark_as_read",
293 web::post().to(route_post::<MarkPersonMentionAsRead>),
295 .route("/replies", web::get().to(route_get::<GetReplies>))
296 // Admin action. I don't like that it's in /user
297 .route("/ban", web::post().to(route_post::<BanPerson>))
298 .route("/banned", web::get().to(route_get::<GetBannedPersons>))
299 .route("/block", web::post().to(route_post::<BlockPerson>))
300 // Account actions. I don't like that they're in /user maybe /accounts
301 .route("/login", web::post().to(route_post::<Login>))
304 web::post().to(route_post_crud::<DeleteAccount>),
308 web::post().to(route_post::<PasswordReset>),
312 web::post().to(route_post::<PasswordChangeAfterReset>),
314 // mark_all_as_read feels off being in this section as well
317 web::post().to(route_post::<MarkAllAsRead>),
320 "/save_user_settings",
321 web::put().to(route_post::<SaveUserSettings>),
325 web::put().to(route_post::<ChangePassword>),
327 .route("/report_count", web::get().to(route_get::<GetReportCount>))
328 .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
329 .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
330 .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
335 .wrap(rate_limit.message())
336 .route("/add", web::post().to(route_post::<AddAdmin>))
338 "/registration_application/count",
339 web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
342 "/registration_application/list",
343 web::get().to(route_get::<ListRegistrationApplications>),
346 "/registration_application/approve",
347 web::put().to(route_post::<ApproveRegistrationApplication>),
351 .route("/person", web::post().to(route_post::<PurgePerson>))
352 .route("/community", web::post().to(route_post::<PurgeCommunity>))
353 .route("/post", web::post().to(route_post::<PurgePost>))
354 .route("/comment", web::post().to(route_post::<PurgeComment>)),
358 web::scope("/custom_emoji")
359 .wrap(rate_limit.message())
360 .route("", web::post().to(route_post_crud::<CreateCustomEmoji>))
361 .route("", web::put().to(route_post_crud::<EditCustomEmoji>))
364 web::post().to(route_post_crud::<DeleteCustomEmoji>),
370 async fn perform<'a, Data>(
372 context: web::Data<LemmyContext>,
373 apub_data: activitypub_federation::config::Data<LemmyContext>,
374 ) -> Result<HttpResponse, Error>
377 + SendActivity<Response = <Data as Perform>::Response>
383 let res = data.perform(&context).await?;
384 let res_clone = res.clone();
385 let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await };
386 if *SYNCHRONOUS_FEDERATION {
389 spawn_try_task(fed_task);
391 Ok(HttpResponse::Ok().json(&res))
394 async fn route_get<'a, Data>(
395 data: web::Query<Data>,
396 context: web::Data<LemmyContext>,
397 apub_data: activitypub_federation::config::Data<LemmyContext>,
398 ) -> Result<HttpResponse, Error>
401 + SendActivity<Response = <Data as Perform>::Response>
407 perform::<Data>(data.0, context, apub_data).await
410 async fn route_post<'a, Data>(
411 data: web::Json<Data>,
412 context: web::Data<LemmyContext>,
413 apub_data: activitypub_federation::config::Data<LemmyContext>,
414 ) -> Result<HttpResponse, Error>
417 + SendActivity<Response = <Data as Perform>::Response>
423 perform::<Data>(data.0, context, apub_data).await
426 async fn perform_crud<'a, Data>(
428 context: web::Data<LemmyContext>,
429 apub_data: activitypub_federation::config::Data<LemmyContext>,
430 ) -> Result<HttpResponse, Error>
433 + SendActivity<Response = <Data as PerformCrud>::Response>
439 let res = data.perform(&context).await?;
440 let res_clone = res.clone();
441 let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await };
442 if *SYNCHRONOUS_FEDERATION {
445 spawn_try_task(fed_task);
447 Ok(HttpResponse::Ok().json(&res))
450 async fn route_get_crud<'a, Data>(
451 data: web::Query<Data>,
452 context: web::Data<LemmyContext>,
453 apub_data: activitypub_federation::config::Data<LemmyContext>,
454 ) -> Result<HttpResponse, Error>
457 + SendActivity<Response = <Data as PerformCrud>::Response>
463 perform_crud::<Data>(data.0, context, apub_data).await
466 async fn route_post_crud<'a, Data>(
467 data: web::Json<Data>,
468 context: web::Data<LemmyContext>,
469 apub_data: activitypub_federation::config::Data<LemmyContext>,
470 ) -> Result<HttpResponse, Error>
473 + SendActivity<Response = <Data as PerformCrud>::Response>
479 perform_crud::<Data>(data.0, context, apub_data).await