1 use actix_web::{guard, web, Error, HttpResponse, Result};
3 comment::{distinguish::distinguish_comment, save::save_comment},
4 comment_report::{list::list_comment_reports, resolve::resolve_comment_report},
5 local_user::notifications::mark_reply_read::mark_reply_as_read,
8 use lemmy_api_common::{
9 comment::{CreateCommentLike, CreateCommentReport, DeleteComment, EditComment, RemoveComment},
22 context::LemmyContext,
23 custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji},
38 MarkPersonMentionAsRead,
39 PasswordChangeAfterReset,
61 CreatePrivateMessageReport,
64 ListPrivateMessageReports,
65 MarkPrivateMessageAsRead,
66 ResolvePrivateMessageReport,
69 ApproveRegistrationApplication,
70 GetFederatedInstances,
72 GetUnreadRegistrationApplicationCount,
74 ListRegistrationApplications,
82 comment::{create::create_comment, read::get_comment},
83 community::list::list_communities,
84 post::{create::create_post, read::get_post},
85 private_message::read::get_private_message,
86 site::{create::create_site, read::get_site, update::update_site},
91 list_comments::list_comments,
92 list_posts::list_posts,
93 read_community::get_community,
94 read_person::read_person,
95 resolve_object::resolve_object,
100 use lemmy_utils::{rate_limit::RateLimitCell, spawn_try_task, SYNCHRONOUS_FEDERATION};
101 use serde::Deserialize;
103 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
105 web::scope("/api/v3")
109 .wrap(rate_limit.message())
110 .route("", web::get().to(get_site))
112 .route("", web::post().to(create_site))
113 .route("", web::put().to(update_site)),
116 web::resource("/modlog")
117 .wrap(rate_limit.message())
118 .route(web::get().to(route_get::<GetModlog>)),
121 web::resource("/search")
122 .wrap(rate_limit.search())
123 .route(web::get().to(search)),
126 web::resource("/resolve_object")
127 .wrap(rate_limit.message())
128 .route(web::get().to(resolve_object)),
132 web::resource("/community")
133 .guard(guard::Post())
134 .wrap(rate_limit.register())
135 .route(web::post().to(route_post_crud::<CreateCommunity>)),
138 web::scope("/community")
139 .wrap(rate_limit.message())
140 .route("", web::get().to(get_community))
141 .route("", web::put().to(route_post_crud::<EditCommunity>))
142 .route("/hide", web::put().to(route_post::<HideCommunity>))
143 .route("/list", web::get().to(list_communities))
144 .route("/follow", web::post().to(route_post::<FollowCommunity>))
145 .route("/block", web::post().to(route_post::<BlockCommunity>))
148 web::post().to(route_post_crud::<DeleteCommunity>),
153 web::post().to(route_post_crud::<RemoveCommunity>),
155 .route("/transfer", web::post().to(route_post::<TransferCommunity>))
156 .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
157 .route("/mod", web::post().to(route_post::<AddModToCommunity>)),
160 web::scope("/federated_instances")
161 .wrap(rate_limit.message())
162 .route("", web::get().to(route_get::<GetFederatedInstances>)),
166 // Handle POST to /post separately to add the post() rate limitter
167 web::resource("/post")
168 .guard(guard::Post())
169 .wrap(rate_limit.post())
170 .route(web::post().to(create_post)),
174 .wrap(rate_limit.message())
175 .route("", web::get().to(get_post))
176 .route("", web::put().to(route_post_crud::<EditPost>))
177 .route("/delete", web::post().to(route_post_crud::<DeletePost>))
178 .route("/remove", web::post().to(route_post_crud::<RemovePost>))
181 web::post().to(route_post::<MarkPostAsRead>),
183 .route("/lock", web::post().to(route_post::<LockPost>))
184 .route("/feature", web::post().to(route_post::<FeaturePost>))
185 .route("/list", web::get().to(list_posts))
186 .route("/like", web::post().to(route_post::<CreatePostLike>))
187 .route("/save", web::put().to(route_post::<SavePost>))
188 .route("/report", web::post().to(route_post::<CreatePostReport>))
191 web::put().to(route_post::<ResolvePostReport>),
193 .route("/report/list", web::get().to(route_get::<ListPostReports>))
196 web::get().to(route_get::<GetSiteMetadata>),
201 // Handle POST to /comment separately to add the comment() rate limitter
202 web::resource("/comment")
203 .guard(guard::Post())
204 .wrap(rate_limit.comment())
205 .route(web::post().to(create_comment)),
208 web::scope("/comment")
209 .wrap(rate_limit.message())
210 .route("", web::get().to(get_comment))
211 .route("", web::put().to(route_post_crud::<EditComment>))
212 .route("/delete", web::post().to(route_post_crud::<DeleteComment>))
213 .route("/remove", web::post().to(route_post_crud::<RemoveComment>))
214 .route("/mark_as_read", web::post().to(mark_reply_as_read))
215 .route("/distinguish", web::post().to(distinguish_comment))
216 .route("/like", web::post().to(route_post::<CreateCommentLike>))
217 .route("/save", web::put().to(save_comment))
218 .route("/list", web::get().to(list_comments))
219 .route("/report", web::post().to(route_post::<CreateCommentReport>))
220 .route("/report/resolve", web::put().to(resolve_comment_report))
221 .route("/report/list", web::get().to(list_comment_reports)),
225 web::scope("/private_message")
226 .wrap(rate_limit.message())
227 .route("/list", web::get().to(get_private_message))
228 .route("", web::post().to(route_post_crud::<CreatePrivateMessage>))
229 .route("", web::put().to(route_post_crud::<EditPrivateMessage>))
232 web::post().to(route_post_crud::<DeletePrivateMessage>),
236 web::post().to(route_post::<MarkPrivateMessageAsRead>),
240 web::post().to(route_post::<CreatePrivateMessageReport>),
244 web::put().to(route_post::<ResolvePrivateMessageReport>),
248 web::get().to(route_get::<ListPrivateMessageReports>),
253 // Account action, I don't like that it's in /user maybe /accounts
254 // Handle /user/register separately to add the register() rate limitter
255 web::resource("/user/register")
256 .guard(guard::Post())
257 .wrap(rate_limit.register())
258 .route(web::post().to(route_post_crud::<Register>)),
261 // Handle captcha separately
262 web::resource("/user/get_captcha")
263 .wrap(rate_limit.post())
264 .route(web::get().to(route_get::<GetCaptcha>)),
269 .wrap(rate_limit.message())
270 .route("", web::get().to(read_person))
271 .route("/mention", web::get().to(route_get::<GetPersonMentions>))
273 "/mention/mark_as_read",
274 web::post().to(route_post::<MarkPersonMentionAsRead>),
276 .route("/replies", web::get().to(route_get::<GetReplies>))
277 // Admin action. I don't like that it's in /user
278 .route("/ban", web::post().to(route_post::<BanPerson>))
279 .route("/banned", web::get().to(route_get::<GetBannedPersons>))
280 .route("/block", web::post().to(route_post::<BlockPerson>))
281 // Account actions. I don't like that they're in /user maybe /accounts
282 .route("/login", web::post().to(route_post::<Login>))
285 web::post().to(route_post_crud::<DeleteAccount>),
289 web::post().to(route_post::<PasswordReset>),
293 web::post().to(route_post::<PasswordChangeAfterReset>),
295 // mark_all_as_read feels off being in this section as well
298 web::post().to(route_post::<MarkAllAsRead>),
301 "/save_user_settings",
302 web::put().to(route_post::<SaveUserSettings>),
306 web::put().to(route_post::<ChangePassword>),
308 .route("/report_count", web::get().to(route_get::<GetReportCount>))
309 .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
310 .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
311 .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
316 .wrap(rate_limit.message())
317 .route("/add", web::post().to(route_post::<AddAdmin>))
319 "/registration_application/count",
320 web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
323 "/registration_application/list",
324 web::get().to(route_get::<ListRegistrationApplications>),
327 "/registration_application/approve",
328 web::put().to(route_post::<ApproveRegistrationApplication>),
332 .route("/person", web::post().to(route_post::<PurgePerson>))
333 .route("/community", web::post().to(route_post::<PurgeCommunity>))
334 .route("/post", web::post().to(route_post::<PurgePost>))
335 .route("/comment", web::post().to(route_post::<PurgeComment>)),
339 web::scope("/custom_emoji")
340 .wrap(rate_limit.message())
341 .route("", web::post().to(route_post_crud::<CreateCustomEmoji>))
342 .route("", web::put().to(route_post_crud::<EditCustomEmoji>))
345 web::post().to(route_post_crud::<DeleteCustomEmoji>),
351 async fn perform<'a, Data>(
353 context: web::Data<LemmyContext>,
354 apub_data: activitypub_federation::config::Data<LemmyContext>,
355 ) -> Result<HttpResponse, Error>
358 + SendActivity<Response = <Data as Perform>::Response>
364 let res = data.perform(&context).await?;
365 let res_clone = res.clone();
366 let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await };
367 if *SYNCHRONOUS_FEDERATION {
370 spawn_try_task(fed_task);
372 Ok(HttpResponse::Ok().json(&res))
375 async fn route_get<'a, Data>(
376 data: web::Query<Data>,
377 context: web::Data<LemmyContext>,
378 apub_data: activitypub_federation::config::Data<LemmyContext>,
379 ) -> Result<HttpResponse, Error>
382 + SendActivity<Response = <Data as Perform>::Response>
388 perform::<Data>(data.0, context, apub_data).await
391 async fn route_post<'a, Data>(
392 data: web::Json<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 perform_crud<'a, Data>(
409 context: web::Data<LemmyContext>,
410 apub_data: activitypub_federation::config::Data<LemmyContext>,
411 ) -> Result<HttpResponse, Error>
414 + SendActivity<Response = <Data as PerformCrud>::Response>
420 let res = data.perform(&context).await?;
421 let res_clone = res.clone();
422 let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await };
423 if *SYNCHRONOUS_FEDERATION {
426 spawn_try_task(fed_task);
428 Ok(HttpResponse::Ok().json(&res))
431 async fn route_post_crud<'a, Data>(
432 data: web::Json<Data>,
433 context: web::Data<LemmyContext>,
434 apub_data: activitypub_federation::config::Data<LemmyContext>,
435 ) -> Result<HttpResponse, Error>
438 + SendActivity<Response = <Data as PerformCrud>::Response>
444 perform_crud::<Data>(data.0, context, apub_data).await