1 use crate::api_routes_websocket::websocket;
2 use actix_web::{guard, web, Error, HttpResponse, Result};
3 use lemmy_api::Perform;
4 use lemmy_api_common::{
33 context::LemmyContext,
34 custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji},
50 MarkCommentReplyAsRead,
51 MarkPersonMentionAsRead,
52 PasswordChangeAfterReset,
77 CreatePrivateMessageReport,
81 ListPrivateMessageReports,
82 MarkPrivateMessageAsRead,
83 ResolvePrivateMessageReport,
86 ApproveRegistrationApplication,
89 GetFederatedInstances,
92 GetUnreadRegistrationApplicationCount,
94 ListRegistrationApplications,
102 websocket::structs::{CommunityJoin, ModJoin, PostJoin, UserJoin},
104 use lemmy_api_crud::PerformCrud;
105 use lemmy_apub::{api::PerformApub, SendActivity};
106 use lemmy_utils::rate_limit::RateLimitCell;
107 use serde::Deserialize;
109 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
111 web::scope("/api/v3")
113 .service(web::resource("/ws").to(websocket))
117 .wrap(rate_limit.message())
118 .route("", web::get().to(route_get_crud::<GetSite>))
120 .route("", web::post().to(route_post_crud::<CreateSite>))
121 .route("", web::put().to(route_post_crud::<EditSite>)),
124 web::resource("/modlog")
125 .wrap(rate_limit.message())
126 .route(web::get().to(route_get::<GetModlog>)),
129 web::resource("/search")
130 .wrap(rate_limit.search())
131 .route(web::get().to(route_get_apub::<Search>)),
134 web::resource("/resolve_object")
135 .wrap(rate_limit.message())
136 .route(web::get().to(route_get_apub::<ResolveObject>)),
140 web::resource("/community")
141 .guard(guard::Post())
142 .wrap(rate_limit.register())
143 .route(web::post().to(route_post_crud::<CreateCommunity>)),
146 web::scope("/community")
147 .wrap(rate_limit.message())
148 .route("", web::get().to(route_get_apub::<GetCommunity>))
149 .route("", web::put().to(route_post_crud::<EditCommunity>))
150 .route("/hide", web::put().to(route_post::<HideCommunity>))
151 .route("/list", web::get().to(route_get_crud::<ListCommunities>))
152 .route("/follow", web::post().to(route_post::<FollowCommunity>))
153 .route("/block", web::post().to(route_post::<BlockCommunity>))
156 web::post().to(route_post_crud::<DeleteCommunity>),
161 web::post().to(route_post_crud::<RemoveCommunity>),
163 .route("/transfer", web::post().to(route_post::<TransferCommunity>))
164 .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
165 .route("/mod", web::post().to(route_post::<AddModToCommunity>))
166 .route("/join", web::post().to(route_post::<CommunityJoin>))
167 .route("/mod/join", web::post().to(route_post::<ModJoin>)),
170 web::scope("/federated_instances")
171 .wrap(rate_limit.message())
172 .route("", web::get().to(route_get::<GetFederatedInstances>)),
176 // Handle POST to /post separately to add the post() rate limitter
177 web::resource("/post")
178 .guard(guard::Post())
179 .wrap(rate_limit.post())
180 .route(web::post().to(route_post_crud::<CreatePost>)),
184 .wrap(rate_limit.message())
185 .route("", web::get().to(route_get_crud::<GetPost>))
186 .route("", web::put().to(route_post_crud::<EditPost>))
187 .route("/delete", web::post().to(route_post_crud::<DeletePost>))
188 .route("/remove", web::post().to(route_post_crud::<RemovePost>))
191 web::post().to(route_post::<MarkPostAsRead>),
193 .route("/lock", web::post().to(route_post::<LockPost>))
194 .route("/feature", web::post().to(route_post::<FeaturePost>))
195 .route("/list", web::get().to(route_get_apub::<GetPosts>))
196 .route("/like", web::post().to(route_post::<CreatePostLike>))
197 .route("/save", web::put().to(route_post::<SavePost>))
198 .route("/join", web::post().to(route_post::<PostJoin>))
199 .route("/report", web::post().to(route_post::<CreatePostReport>))
202 web::put().to(route_post::<ResolvePostReport>),
204 .route("/report/list", web::get().to(route_get::<ListPostReports>))
207 web::get().to(route_get::<GetSiteMetadata>),
212 // Handle POST to /comment separately to add the comment() rate limitter
213 web::resource("/comment")
214 .guard(guard::Post())
215 .wrap(rate_limit.comment())
216 .route(web::post().to(route_post_crud::<CreateComment>)),
219 web::scope("/comment")
220 .wrap(rate_limit.message())
221 .route("", web::get().to(route_get_crud::<GetComment>))
222 .route("", web::put().to(route_post_crud::<EditComment>))
223 .route("/delete", web::post().to(route_post_crud::<DeleteComment>))
224 .route("/remove", web::post().to(route_post_crud::<RemoveComment>))
227 web::post().to(route_post::<MarkCommentReplyAsRead>),
231 web::post().to(route_post::<DistinguishComment>),
233 .route("/like", web::post().to(route_post::<CreateCommentLike>))
234 .route("/save", web::put().to(route_post::<SaveComment>))
235 .route("/list", web::get().to(route_get_apub::<GetComments>))
236 .route("/report", web::post().to(route_post::<CreateCommentReport>))
239 web::put().to(route_post::<ResolveCommentReport>),
243 web::get().to(route_get::<ListCommentReports>),
248 web::scope("/private_message")
249 .wrap(rate_limit.message())
250 .route("/list", web::get().to(route_get_crud::<GetPrivateMessages>))
251 .route("", web::post().to(route_post_crud::<CreatePrivateMessage>))
252 .route("", web::put().to(route_post_crud::<EditPrivateMessage>))
255 web::post().to(route_post_crud::<DeletePrivateMessage>),
259 web::post().to(route_post::<MarkPrivateMessageAsRead>),
263 web::post().to(route_post::<CreatePrivateMessageReport>),
267 web::put().to(route_post::<ResolvePrivateMessageReport>),
271 web::get().to(route_get::<ListPrivateMessageReports>),
276 // Account action, I don't like that it's in /user maybe /accounts
277 // Handle /user/register separately to add the register() rate limitter
278 web::resource("/user/register")
279 .guard(guard::Post())
280 .wrap(rate_limit.register())
281 .route(web::post().to(route_post_crud::<Register>)),
284 // Handle captcha separately
285 web::resource("/user/get_captcha")
286 .wrap(rate_limit.post())
287 .route(web::get().to(route_get::<GetCaptcha>)),
292 .wrap(rate_limit.message())
293 .route("", web::get().to(route_get_apub::<GetPersonDetails>))
294 .route("/mention", web::get().to(route_get::<GetPersonMentions>))
296 "/mention/mark_as_read",
297 web::post().to(route_post::<MarkPersonMentionAsRead>),
299 .route("/replies", web::get().to(route_get::<GetReplies>))
300 .route("/join", web::post().to(route_post::<UserJoin>))
301 // Admin action. I don't like that it's in /user
302 .route("/ban", web::post().to(route_post::<BanPerson>))
303 .route("/banned", web::get().to(route_get::<GetBannedPersons>))
304 .route("/block", web::post().to(route_post::<BlockPerson>))
305 // Account actions. I don't like that they're in /user maybe /accounts
306 .route("/login", web::post().to(route_post::<Login>))
309 web::post().to(route_post_crud::<DeleteAccount>),
313 web::post().to(route_post::<PasswordReset>),
317 web::post().to(route_post::<PasswordChangeAfterReset>),
319 // mark_all_as_read feels off being in this section as well
322 web::post().to(route_post::<MarkAllAsRead>),
325 "/save_user_settings",
326 web::put().to(route_post::<SaveUserSettings>),
330 web::put().to(route_post::<ChangePassword>),
332 .route("/report_count", web::get().to(route_get::<GetReportCount>))
333 .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
334 .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
335 .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
340 .wrap(rate_limit.message())
341 .route("/add", web::post().to(route_post::<AddAdmin>))
343 "/registration_application/count",
344 web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
347 "/registration_application/list",
348 web::get().to(route_get::<ListRegistrationApplications>),
351 "/registration_application/approve",
352 web::put().to(route_post::<ApproveRegistrationApplication>),
356 web::scope("/admin/purge")
357 .wrap(rate_limit.message())
358 .route("/person", web::post().to(route_post::<PurgePerson>))
359 .route("/community", web::post().to(route_post::<PurgeCommunity>))
360 .route("/post", web::post().to(route_post::<PurgePost>))
361 .route("/comment", web::post().to(route_post::<PurgeComment>)),
364 web::scope("/custom_emoji")
365 .wrap(rate_limit.message())
366 .route("", web::post().to(route_post_crud::<CreateCustomEmoji>))
367 .route("", web::put().to(route_post_crud::<EditCustomEmoji>))
370 web::post().to(route_post_crud::<DeleteCustomEmoji>),
376 async fn perform<'a, Data>(
378 context: web::Data<LemmyContext>,
379 apub_data: activitypub_federation::config::Data<LemmyContext>,
380 ) -> Result<HttpResponse, Error>
383 + SendActivity<Response = <Data as Perform>::Response>
389 let res = data.perform(&context, None).await?;
390 SendActivity::send_activity(&data, &res, &apub_data).await?;
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_get_apub<'a, Data>(
411 data: web::Query<Data>,
412 context: activitypub_federation::config::Data<LemmyContext>,
413 ) -> Result<HttpResponse, Error>
416 + SendActivity<Response = <Data as PerformApub>::Response>
422 let res = data.perform(&context, None).await?;
423 SendActivity::send_activity(&data.0, &res, &context).await?;
424 Ok(HttpResponse::Ok().json(res))
427 async fn route_post<'a, Data>(
428 data: web::Json<Data>,
429 context: web::Data<LemmyContext>,
430 apub_data: activitypub_federation::config::Data<LemmyContext>,
431 ) -> Result<HttpResponse, Error>
434 + SendActivity<Response = <Data as Perform>::Response>
440 perform::<Data>(data.0, context, apub_data).await
443 async fn perform_crud<'a, Data>(
445 context: web::Data<LemmyContext>,
446 apub_data: activitypub_federation::config::Data<LemmyContext>,
447 ) -> Result<HttpResponse, Error>
450 + SendActivity<Response = <Data as PerformCrud>::Response>
456 let res = data.perform(&context, None).await?;
457 SendActivity::send_activity(&data, &res, &apub_data).await?;
458 Ok(HttpResponse::Ok().json(res))
461 async fn route_get_crud<'a, Data>(
462 data: web::Query<Data>,
463 context: web::Data<LemmyContext>,
464 apub_data: activitypub_federation::config::Data<LemmyContext>,
465 ) -> Result<HttpResponse, Error>
468 + SendActivity<Response = <Data as PerformCrud>::Response>
474 perform_crud::<Data>(data.0, context, apub_data).await
477 async fn route_post_crud<'a, Data>(
478 data: web::Json<Data>,
479 context: web::Data<LemmyContext>,
480 apub_data: activitypub_federation::config::Data<LemmyContext>,
481 ) -> Result<HttpResponse, Error>
484 + SendActivity<Response = <Data as PerformCrud>::Response>
490 perform_crud::<Data>(data.0, context, apub_data).await