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