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