]> Untitled Git - lemmy.git/blob - src/api_routes_http.rs
feat: re-added captcha checks (#3249)
[lemmy.git] / src / api_routes_http.rs
1 use actix_web::{guard, web, Error, HttpResponse, Result};
2 use lemmy_api::Perform;
3 use lemmy_api_common::{
4   comment::{
5     CreateComment,
6     CreateCommentLike,
7     CreateCommentReport,
8     DeleteComment,
9     DistinguishComment,
10     EditComment,
11     GetComment,
12     GetComments,
13     ListCommentReports,
14     RemoveComment,
15     ResolveCommentReport,
16     SaveComment,
17   },
18   community::{
19     AddModToCommunity,
20     BanFromCommunity,
21     BlockCommunity,
22     CreateCommunity,
23     DeleteCommunity,
24     EditCommunity,
25     FollowCommunity,
26     GetCommunity,
27     HideCommunity,
28     ListCommunities,
29     RemoveCommunity,
30     TransferCommunity,
31   },
32   context::LemmyContext,
33   custom_emoji::{CreateCustomEmoji, DeleteCustomEmoji, EditCustomEmoji},
34   person::{
35     AddAdmin,
36     BanPerson,
37     BlockPerson,
38     ChangePassword,
39     DeleteAccount,
40     GetBannedPersons,
41     GetCaptcha,
42     GetPersonDetails,
43     GetPersonMentions,
44     GetReplies,
45     GetReportCount,
46     GetUnreadCount,
47     Login,
48     MarkAllAsRead,
49     MarkCommentReplyAsRead,
50     MarkPersonMentionAsRead,
51     PasswordChangeAfterReset,
52     PasswordReset,
53     Register,
54     SaveUserSettings,
55     VerifyEmail,
56   },
57   post::{
58     CreatePost,
59     CreatePostLike,
60     CreatePostReport,
61     DeletePost,
62     EditPost,
63     FeaturePost,
64     GetPost,
65     GetPosts,
66     GetSiteMetadata,
67     ListPostReports,
68     LockPost,
69     MarkPostAsRead,
70     RemovePost,
71     ResolvePostReport,
72     SavePost,
73   },
74   private_message::{
75     CreatePrivateMessage,
76     CreatePrivateMessageReport,
77     DeletePrivateMessage,
78     EditPrivateMessage,
79     GetPrivateMessages,
80     ListPrivateMessageReports,
81     MarkPrivateMessageAsRead,
82     ResolvePrivateMessageReport,
83   },
84   site::{
85     ApproveRegistrationApplication,
86     CreateSite,
87     EditSite,
88     GetFederatedInstances,
89     GetModlog,
90     GetSite,
91     GetUnreadRegistrationApplicationCount,
92     LeaveAdmin,
93     ListRegistrationApplications,
94     PurgeComment,
95     PurgeCommunity,
96     PurgePerson,
97     PurgePost,
98     ResolveObject,
99     Search,
100   },
101 };
102 use lemmy_api_crud::PerformCrud;
103 use lemmy_apub::{api::PerformApub, SendActivity};
104 use lemmy_utils::rate_limit::RateLimitCell;
105 use serde::Deserialize;
106
107 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
108   cfg.service(
109     web::scope("/api/v3")
110       // Site
111       .service(
112         web::scope("/site")
113           .wrap(rate_limit.message())
114           .route("", web::get().to(route_get_crud::<GetSite>))
115           // Admin Actions
116           .route("", web::post().to(route_post_crud::<CreateSite>))
117           .route("", web::put().to(route_post_crud::<EditSite>)),
118       )
119       .service(
120         web::resource("/modlog")
121           .wrap(rate_limit.message())
122           .route(web::get().to(route_get::<GetModlog>)),
123       )
124       .service(
125         web::resource("/search")
126           .wrap(rate_limit.search())
127           .route(web::get().to(route_get_apub::<Search>)),
128       )
129       .service(
130         web::resource("/resolve_object")
131           .wrap(rate_limit.message())
132           .route(web::get().to(route_get_apub::<ResolveObject>)),
133       )
134       // Community
135       .service(
136         web::resource("/community")
137           .guard(guard::Post())
138           .wrap(rate_limit.register())
139           .route(web::post().to(route_post_crud::<CreateCommunity>)),
140       )
141       .service(
142         web::scope("/community")
143           .wrap(rate_limit.message())
144           .route("", web::get().to(route_get_apub::<GetCommunity>))
145           .route("", web::put().to(route_post_crud::<EditCommunity>))
146           .route("/hide", web::put().to(route_post::<HideCommunity>))
147           .route("/list", web::get().to(route_get_crud::<ListCommunities>))
148           .route("/follow", web::post().to(route_post::<FollowCommunity>))
149           .route("/block", web::post().to(route_post::<BlockCommunity>))
150           .route(
151             "/delete",
152             web::post().to(route_post_crud::<DeleteCommunity>),
153           )
154           // Mod Actions
155           .route(
156             "/remove",
157             web::post().to(route_post_crud::<RemoveCommunity>),
158           )
159           .route("/transfer", web::post().to(route_post::<TransferCommunity>))
160           .route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
161           .route("/mod", web::post().to(route_post::<AddModToCommunity>)),
162       )
163       .service(
164         web::scope("/federated_instances")
165           .wrap(rate_limit.message())
166           .route("", web::get().to(route_get::<GetFederatedInstances>)),
167       )
168       // Post
169       .service(
170         // Handle POST to /post separately to add the post() rate limitter
171         web::resource("/post")
172           .guard(guard::Post())
173           .wrap(rate_limit.post())
174           .route(web::post().to(route_post_crud::<CreatePost>)),
175       )
176       .service(
177         web::scope("/post")
178           .wrap(rate_limit.message())
179           .route("", web::get().to(route_get_crud::<GetPost>))
180           .route("", web::put().to(route_post_crud::<EditPost>))
181           .route("/delete", web::post().to(route_post_crud::<DeletePost>))
182           .route("/remove", web::post().to(route_post_crud::<RemovePost>))
183           .route(
184             "/mark_as_read",
185             web::post().to(route_post::<MarkPostAsRead>),
186           )
187           .route("/lock", web::post().to(route_post::<LockPost>))
188           .route("/feature", web::post().to(route_post::<FeaturePost>))
189           .route("/list", web::get().to(route_get_apub::<GetPosts>))
190           .route("/like", web::post().to(route_post::<CreatePostLike>))
191           .route("/save", web::put().to(route_post::<SavePost>))
192           .route("/report", web::post().to(route_post::<CreatePostReport>))
193           .route(
194             "/report/resolve",
195             web::put().to(route_post::<ResolvePostReport>),
196           )
197           .route("/report/list", web::get().to(route_get::<ListPostReports>))
198           .route(
199             "/site_metadata",
200             web::get().to(route_get::<GetSiteMetadata>),
201           ),
202       )
203       // Comment
204       .service(
205         // Handle POST to /comment separately to add the comment() rate limitter
206         web::resource("/comment")
207           .guard(guard::Post())
208           .wrap(rate_limit.comment())
209           .route(web::post().to(route_post_crud::<CreateComment>)),
210       )
211       .service(
212         web::scope("/comment")
213           .wrap(rate_limit.message())
214           .route("", web::get().to(route_get_crud::<GetComment>))
215           .route("", web::put().to(route_post_crud::<EditComment>))
216           .route("/delete", web::post().to(route_post_crud::<DeleteComment>))
217           .route("/remove", web::post().to(route_post_crud::<RemoveComment>))
218           .route(
219             "/mark_as_read",
220             web::post().to(route_post::<MarkCommentReplyAsRead>),
221           )
222           .route(
223             "/distinguish",
224             web::post().to(route_post::<DistinguishComment>),
225           )
226           .route("/like", web::post().to(route_post::<CreateCommentLike>))
227           .route("/save", web::put().to(route_post::<SaveComment>))
228           .route("/list", web::get().to(route_get_apub::<GetComments>))
229           .route("/report", web::post().to(route_post::<CreateCommentReport>))
230           .route(
231             "/report/resolve",
232             web::put().to(route_post::<ResolveCommentReport>),
233           )
234           .route(
235             "/report/list",
236             web::get().to(route_get::<ListCommentReports>),
237           ),
238       )
239       // Private Message
240       .service(
241         web::scope("/private_message")
242           .wrap(rate_limit.message())
243           .route("/list", web::get().to(route_get_crud::<GetPrivateMessages>))
244           .route("", web::post().to(route_post_crud::<CreatePrivateMessage>))
245           .route("", web::put().to(route_post_crud::<EditPrivateMessage>))
246           .route(
247             "/delete",
248             web::post().to(route_post_crud::<DeletePrivateMessage>),
249           )
250           .route(
251             "/mark_as_read",
252             web::post().to(route_post::<MarkPrivateMessageAsRead>),
253           )
254           .route(
255             "/report",
256             web::post().to(route_post::<CreatePrivateMessageReport>),
257           )
258           .route(
259             "/report/resolve",
260             web::put().to(route_post::<ResolvePrivateMessageReport>),
261           )
262           .route(
263             "/report/list",
264             web::get().to(route_get::<ListPrivateMessageReports>),
265           ),
266       )
267       // User
268       .service(
269         // Account action, I don't like that it's in /user maybe /accounts
270         // Handle /user/register separately to add the register() rate limitter
271         web::resource("/user/register")
272           .guard(guard::Post())
273           .wrap(rate_limit.register())
274           .route(web::post().to(route_post_crud::<Register>)),
275       )
276       .service(
277         // Handle captcha separately
278         web::resource("/user/get_captcha")
279           .wrap(rate_limit.post())
280           .route(web::get().to(route_get::<GetCaptcha>)),
281       )
282       // User actions
283       .service(
284         web::scope("/user")
285           .wrap(rate_limit.message())
286           .route("", web::get().to(route_get_apub::<GetPersonDetails>))
287           .route("/mention", web::get().to(route_get::<GetPersonMentions>))
288           .route(
289             "/mention/mark_as_read",
290             web::post().to(route_post::<MarkPersonMentionAsRead>),
291           )
292           .route("/replies", web::get().to(route_get::<GetReplies>))
293           // Admin action. I don't like that it's in /user
294           .route("/ban", web::post().to(route_post::<BanPerson>))
295           .route("/banned", web::get().to(route_get::<GetBannedPersons>))
296           .route("/block", web::post().to(route_post::<BlockPerson>))
297           // Account actions. I don't like that they're in /user maybe /accounts
298           .route("/login", web::post().to(route_post::<Login>))
299           .route(
300             "/delete_account",
301             web::post().to(route_post_crud::<DeleteAccount>),
302           )
303           .route(
304             "/password_reset",
305             web::post().to(route_post::<PasswordReset>),
306           )
307           .route(
308             "/password_change",
309             web::post().to(route_post::<PasswordChangeAfterReset>),
310           )
311           // mark_all_as_read feels off being in this section as well
312           .route(
313             "/mark_all_as_read",
314             web::post().to(route_post::<MarkAllAsRead>),
315           )
316           .route(
317             "/save_user_settings",
318             web::put().to(route_post::<SaveUserSettings>),
319           )
320           .route(
321             "/change_password",
322             web::put().to(route_post::<ChangePassword>),
323           )
324           .route("/report_count", web::get().to(route_get::<GetReportCount>))
325           .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
326           .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
327           .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
328       )
329       // Admin Actions
330       .service(
331         web::scope("/admin")
332           .wrap(rate_limit.message())
333           .route("/add", web::post().to(route_post::<AddAdmin>))
334           .route(
335             "/registration_application/count",
336             web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
337           )
338           .route(
339             "/registration_application/list",
340             web::get().to(route_get::<ListRegistrationApplications>),
341           )
342           .route(
343             "/registration_application/approve",
344             web::put().to(route_post::<ApproveRegistrationApplication>),
345           )
346           .service(
347             web::scope("/purge")
348               .route("/person", web::post().to(route_post::<PurgePerson>))
349               .route("/community", web::post().to(route_post::<PurgeCommunity>))
350               .route("/post", web::post().to(route_post::<PurgePost>))
351               .route("/comment", web::post().to(route_post::<PurgeComment>)),
352           ),
353       )
354       .service(
355         web::scope("/custom_emoji")
356           .wrap(rate_limit.message())
357           .route("", web::post().to(route_post_crud::<CreateCustomEmoji>))
358           .route("", web::put().to(route_post_crud::<EditCustomEmoji>))
359           .route(
360             "/delete",
361             web::post().to(route_post_crud::<DeleteCustomEmoji>),
362           ),
363       ),
364   );
365 }
366
367 async fn perform<'a, Data>(
368   data: Data,
369   context: web::Data<LemmyContext>,
370   apub_data: activitypub_federation::config::Data<LemmyContext>,
371 ) -> Result<HttpResponse, Error>
372 where
373   Data: Perform
374     + SendActivity<Response = <Data as Perform>::Response>
375     + Clone
376     + Deserialize<'a>
377     + Send
378     + 'static,
379 {
380   let res = data.perform(&context).await?;
381   SendActivity::send_activity(&data, &res, &apub_data).await?;
382   Ok(HttpResponse::Ok().json(res))
383 }
384
385 async fn route_get<'a, Data>(
386   data: web::Query<Data>,
387   context: web::Data<LemmyContext>,
388   apub_data: activitypub_federation::config::Data<LemmyContext>,
389 ) -> Result<HttpResponse, Error>
390 where
391   Data: Perform
392     + SendActivity<Response = <Data as Perform>::Response>
393     + Clone
394     + Deserialize<'a>
395     + Send
396     + 'static,
397 {
398   perform::<Data>(data.0, context, apub_data).await
399 }
400
401 async fn route_get_apub<'a, Data>(
402   data: web::Query<Data>,
403   context: activitypub_federation::config::Data<LemmyContext>,
404 ) -> Result<HttpResponse, Error>
405 where
406   Data: PerformApub
407     + SendActivity<Response = <Data as PerformApub>::Response>
408     + Clone
409     + Deserialize<'a>
410     + Send
411     + 'static,
412 {
413   let res = data.perform(&context).await?;
414   SendActivity::send_activity(&data.0, &res, &context).await?;
415   Ok(HttpResponse::Ok().json(res))
416 }
417
418 async fn route_post<'a, Data>(
419   data: web::Json<Data>,
420   context: web::Data<LemmyContext>,
421   apub_data: activitypub_federation::config::Data<LemmyContext>,
422 ) -> Result<HttpResponse, Error>
423 where
424   Data: Perform
425     + SendActivity<Response = <Data as Perform>::Response>
426     + Clone
427     + Deserialize<'a>
428     + Send
429     + 'static,
430 {
431   perform::<Data>(data.0, context, apub_data).await
432 }
433
434 async fn perform_crud<'a, Data>(
435   data: Data,
436   context: web::Data<LemmyContext>,
437   apub_data: activitypub_federation::config::Data<LemmyContext>,
438 ) -> Result<HttpResponse, Error>
439 where
440   Data: PerformCrud
441     + SendActivity<Response = <Data as PerformCrud>::Response>
442     + Clone
443     + Deserialize<'a>
444     + Send
445     + 'static,
446 {
447   let res = data.perform(&context).await?;
448   SendActivity::send_activity(&data, &res, &apub_data).await?;
449   Ok(HttpResponse::Ok().json(res))
450 }
451
452 async fn route_get_crud<'a, Data>(
453   data: web::Query<Data>,
454   context: web::Data<LemmyContext>,
455   apub_data: activitypub_federation::config::Data<LemmyContext>,
456 ) -> Result<HttpResponse, Error>
457 where
458   Data: PerformCrud
459     + SendActivity<Response = <Data as PerformCrud>::Response>
460     + Clone
461     + Deserialize<'a>
462     + Send
463     + 'static,
464 {
465   perform_crud::<Data>(data.0, context, apub_data).await
466 }
467
468 async fn route_post_crud<'a, Data>(
469   data: web::Json<Data>,
470   context: web::Data<LemmyContext>,
471   apub_data: activitypub_federation::config::Data<LemmyContext>,
472 ) -> Result<HttpResponse, Error>
473 where
474   Data: PerformCrud
475     + SendActivity<Response = <Data as PerformCrud>::Response>
476     + Clone
477     + Deserialize<'a>
478     + Send
479     + 'static,
480 {
481   perform_crud::<Data>(data.0, context, apub_data).await
482 }