]> Untitled Git - lemmy.git/blob - src/api_routes_http.rs
Rewrite remaining federation actions, get rid of PerformCrud trait (#3794)
[lemmy.git] / src / api_routes_http.rs
1 use actix_web::{guard, web, Error, HttpResponse, Result};
2 use lemmy_api::{
3   comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment},
4   comment_report::{
5     create::create_comment_report,
6     list::list_comment_reports,
7     resolve::resolve_comment_report,
8   },
9   community::{
10     add_mod::add_mod_to_community,
11     ban::ban_from_community,
12     block::block_community,
13     follow::follow_community,
14     hide::hide_community,
15   },
16   local_user::{ban_person::ban_from_site, notifications::mark_reply_read::mark_reply_as_read},
17   post::{feature::feature_post, like::like_post, lock::lock_post},
18   post_report::create::create_post_report,
19   Perform,
20 };
21 use lemmy_api_common::{
22   community::TransferCommunity,
23   context::LemmyContext,
24   person::{
25     AddAdmin,
26     BlockPerson,
27     ChangePassword,
28     GetBannedPersons,
29     GetCaptcha,
30     GetPersonMentions,
31     GetReplies,
32     GetReportCount,
33     GetUnreadCount,
34     Login,
35     MarkAllAsRead,
36     MarkPersonMentionAsRead,
37     PasswordChangeAfterReset,
38     PasswordReset,
39     SaveUserSettings,
40     VerifyEmail,
41   },
42   post::{GetSiteMetadata, ListPostReports, MarkPostAsRead, ResolvePostReport, SavePost},
43   private_message::{
44     CreatePrivateMessageReport,
45     ListPrivateMessageReports,
46     MarkPrivateMessageAsRead,
47     ResolvePrivateMessageReport,
48   },
49   site::{
50     ApproveRegistrationApplication,
51     GetFederatedInstances,
52     GetModlog,
53     GetUnreadRegistrationApplicationCount,
54     LeaveAdmin,
55     ListRegistrationApplications,
56     PurgeComment,
57     PurgeCommunity,
58     PurgePerson,
59     PurgePost,
60   },
61 };
62 use lemmy_api_crud::{
63   comment::{
64     create::create_comment,
65     delete::delete_comment,
66     read::get_comment,
67     remove::remove_comment,
68     update::update_comment,
69   },
70   community::{
71     create::create_community,
72     delete::delete_community,
73     list::list_communities,
74     remove::remove_community,
75     update::update_community,
76   },
77   custom_emoji::{
78     create::create_custom_emoji,
79     delete::delete_custom_emoji,
80     update::update_custom_emoji,
81   },
82   post::{
83     create::create_post,
84     delete::delete_post,
85     read::get_post,
86     remove::remove_post,
87     update::update_post,
88   },
89   private_message::{
90     create::create_private_message,
91     delete::delete_private_message,
92     read::get_private_message,
93     update::update_private_message,
94   },
95   site::{create::create_site, read::get_site, update::update_site},
96   user::{create::register, delete::delete_account},
97 };
98 use lemmy_apub::{
99   api::{
100     list_comments::list_comments,
101     list_posts::list_posts,
102     read_community::get_community,
103     read_person::read_person,
104     resolve_object::resolve_object,
105     search::search,
106   },
107   SendActivity,
108 };
109 use lemmy_utils::{rate_limit::RateLimitCell, spawn_try_task, SYNCHRONOUS_FEDERATION};
110 use serde::Deserialize;
111
112 pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
113   cfg.service(
114     web::scope("/api/v3")
115       // Site
116       .service(
117         web::scope("/site")
118           .wrap(rate_limit.message())
119           .route("", web::get().to(get_site))
120           // Admin Actions
121           .route("", web::post().to(create_site))
122           .route("", web::put().to(update_site)),
123       )
124       .service(
125         web::resource("/modlog")
126           .wrap(rate_limit.message())
127           .route(web::get().to(route_get::<GetModlog>)),
128       )
129       .service(
130         web::resource("/search")
131           .wrap(rate_limit.search())
132           .route(web::get().to(search)),
133       )
134       .service(
135         web::resource("/resolve_object")
136           .wrap(rate_limit.message())
137           .route(web::get().to(resolve_object)),
138       )
139       // Community
140       .service(
141         web::resource("/community")
142           .guard(guard::Post())
143           .wrap(rate_limit.register())
144           .route(web::post().to(create_community)),
145       )
146       .service(
147         web::scope("/community")
148           .wrap(rate_limit.message())
149           .route("", web::get().to(get_community))
150           .route("", web::put().to(update_community))
151           .route("/hide", web::put().to(hide_community))
152           .route("/list", web::get().to(list_communities))
153           .route("/follow", web::post().to(follow_community))
154           .route("/block", web::post().to(block_community))
155           .route("/delete", web::post().to(delete_community))
156           // Mod Actions
157           .route("/remove", web::post().to(remove_community))
158           .route("/transfer", web::post().to(route_post::<TransferCommunity>))
159           .route("/ban_user", web::post().to(ban_from_community))
160           .route("/mod", web::post().to(add_mod_to_community)),
161       )
162       .service(
163         web::scope("/federated_instances")
164           .wrap(rate_limit.message())
165           .route("", web::get().to(route_get::<GetFederatedInstances>)),
166       )
167       // Post
168       .service(
169         // Handle POST to /post separately to add the post() rate limitter
170         web::resource("/post")
171           .guard(guard::Post())
172           .wrap(rate_limit.post())
173           .route(web::post().to(create_post)),
174       )
175       .service(
176         web::scope("/post")
177           .wrap(rate_limit.message())
178           .route("", web::get().to(get_post))
179           .route("", web::put().to(update_post))
180           .route("/delete", web::post().to(delete_post))
181           .route("/remove", web::post().to(remove_post))
182           .route(
183             "/mark_as_read",
184             web::post().to(route_post::<MarkPostAsRead>),
185           )
186           .route("/lock", web::post().to(lock_post))
187           .route("/feature", web::post().to(feature_post))
188           .route("/list", web::get().to(list_posts))
189           .route("/like", web::post().to(like_post))
190           .route("/save", web::put().to(route_post::<SavePost>))
191           .route("/report", web::post().to(create_post_report))
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(create_comment)),
209       )
210       .service(
211         web::scope("/comment")
212           .wrap(rate_limit.message())
213           .route("", web::get().to(get_comment))
214           .route("", web::put().to(update_comment))
215           .route("/delete", web::post().to(delete_comment))
216           .route("/remove", web::post().to(remove_comment))
217           .route("/mark_as_read", web::post().to(mark_reply_as_read))
218           .route("/distinguish", web::post().to(distinguish_comment))
219           .route("/like", web::post().to(like_comment))
220           .route("/save", web::put().to(save_comment))
221           .route("/list", web::get().to(list_comments))
222           .route("/report", web::post().to(create_comment_report))
223           .route("/report/resolve", web::put().to(resolve_comment_report))
224           .route("/report/list", web::get().to(list_comment_reports)),
225       )
226       // Private Message
227       .service(
228         web::scope("/private_message")
229           .wrap(rate_limit.message())
230           .route("/list", web::get().to(get_private_message))
231           .route("", web::post().to(create_private_message))
232           .route("", web::put().to(update_private_message))
233           .route("/delete", web::post().to(delete_private_message))
234           .route(
235             "/mark_as_read",
236             web::post().to(route_post::<MarkPrivateMessageAsRead>),
237           )
238           .route(
239             "/report",
240             web::post().to(route_post::<CreatePrivateMessageReport>),
241           )
242           .route(
243             "/report/resolve",
244             web::put().to(route_post::<ResolvePrivateMessageReport>),
245           )
246           .route(
247             "/report/list",
248             web::get().to(route_get::<ListPrivateMessageReports>),
249           ),
250       )
251       // User
252       .service(
253         // Account action, I don't like that it's in /user maybe /accounts
254         // Handle /user/register separately to add the register() rate limitter
255         web::resource("/user/register")
256           .guard(guard::Post())
257           .wrap(rate_limit.register())
258           .route(web::post().to(register)),
259       )
260       .service(
261         // Handle captcha separately
262         web::resource("/user/get_captcha")
263           .wrap(rate_limit.post())
264           .route(web::get().to(route_get::<GetCaptcha>)),
265       )
266       // User actions
267       .service(
268         web::scope("/user")
269           .wrap(rate_limit.message())
270           .route("", web::get().to(read_person))
271           .route("/mention", web::get().to(route_get::<GetPersonMentions>))
272           .route(
273             "/mention/mark_as_read",
274             web::post().to(route_post::<MarkPersonMentionAsRead>),
275           )
276           .route("/replies", web::get().to(route_get::<GetReplies>))
277           // Admin action. I don't like that it's in /user
278           .route("/ban", web::post().to(ban_from_site))
279           .route("/banned", web::get().to(route_get::<GetBannedPersons>))
280           .route("/block", web::post().to(route_post::<BlockPerson>))
281           // Account actions. I don't like that they're in /user maybe /accounts
282           .route("/login", web::post().to(route_post::<Login>))
283           .route("/delete_account", web::post().to(delete_account))
284           .route(
285             "/password_reset",
286             web::post().to(route_post::<PasswordReset>),
287           )
288           .route(
289             "/password_change",
290             web::post().to(route_post::<PasswordChangeAfterReset>),
291           )
292           // mark_all_as_read feels off being in this section as well
293           .route(
294             "/mark_all_as_read",
295             web::post().to(route_post::<MarkAllAsRead>),
296           )
297           .route(
298             "/save_user_settings",
299             web::put().to(route_post::<SaveUserSettings>),
300           )
301           .route(
302             "/change_password",
303             web::put().to(route_post::<ChangePassword>),
304           )
305           .route("/report_count", web::get().to(route_get::<GetReportCount>))
306           .route("/unread_count", web::get().to(route_get::<GetUnreadCount>))
307           .route("/verify_email", web::post().to(route_post::<VerifyEmail>))
308           .route("/leave_admin", web::post().to(route_post::<LeaveAdmin>)),
309       )
310       // Admin Actions
311       .service(
312         web::scope("/admin")
313           .wrap(rate_limit.message())
314           .route("/add", web::post().to(route_post::<AddAdmin>))
315           .route(
316             "/registration_application/count",
317             web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
318           )
319           .route(
320             "/registration_application/list",
321             web::get().to(route_get::<ListRegistrationApplications>),
322           )
323           .route(
324             "/registration_application/approve",
325             web::put().to(route_post::<ApproveRegistrationApplication>),
326           )
327           .service(
328             web::scope("/purge")
329               .route("/person", web::post().to(route_post::<PurgePerson>))
330               .route("/community", web::post().to(route_post::<PurgeCommunity>))
331               .route("/post", web::post().to(route_post::<PurgePost>))
332               .route("/comment", web::post().to(route_post::<PurgeComment>)),
333           ),
334       )
335       .service(
336         web::scope("/custom_emoji")
337           .wrap(rate_limit.message())
338           .route("", web::post().to(create_custom_emoji))
339           .route("", web::put().to(update_custom_emoji))
340           .route("/delete", web::post().to(delete_custom_emoji)),
341       ),
342   );
343 }
344
345 async fn perform<'a, Data>(
346   data: Data,
347   context: web::Data<LemmyContext>,
348   apub_data: activitypub_federation::config::Data<LemmyContext>,
349 ) -> Result<HttpResponse, Error>
350 where
351   Data: Perform
352     + SendActivity<Response = <Data as Perform>::Response>
353     + Clone
354     + Deserialize<'a>
355     + Send
356     + 'static,
357 {
358   let res = data.perform(&context).await?;
359   let res_clone = res.clone();
360   let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await };
361   if *SYNCHRONOUS_FEDERATION {
362     fed_task.await?;
363   } else {
364     spawn_try_task(fed_task);
365   }
366   Ok(HttpResponse::Ok().json(&res))
367 }
368
369 async fn route_get<'a, Data>(
370   data: web::Query<Data>,
371   context: web::Data<LemmyContext>,
372   apub_data: activitypub_federation::config::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   perform::<Data>(data.0, context, apub_data).await
383 }
384
385 async fn route_post<'a, Data>(
386   data: web::Json<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 }