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