]> Untitled Git - lemmy.git/blob - server/src/apub/inbox/activities/undo.rs
Merge branch 'main' into inbox-refactoring-dessalines
[lemmy.git] / server / src / apub / inbox / activities / undo.rs
1 use crate::{
2   api::{comment::CommentResponse, community::CommunityResponse, post::PostResponse},
3   apub::{
4     fetcher::{get_or_fetch_and_insert_remote_comment, get_or_fetch_and_insert_remote_post},
5     inbox::shared_inbox::{
6       announce_if_community_is_local, get_user_from_activity, receive_unhandled_activity,
7     },
8     ActorType, FromApub, GroupExt, PageExt,
9   },
10   blocking,
11   routes::ChatServerParam,
12   websocket::{
13     server::{SendComment, SendCommunityRoomMessage, SendPost},
14     UserOperation,
15   },
16   DbPool, LemmyError,
17 };
18 use activitystreams_new::{activity::*, base::AnyBase, object::Note, prelude::*};
19 use actix_web::{client::Client, HttpResponse};
20 use lemmy_db::{
21   comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
22   comment_view::CommentView,
23   community::{Community, CommunityForm},
24   community_view::CommunityView,
25   naive_now,
26   post::{Post, PostForm, PostLike, PostLikeForm},
27   post_view::PostView,
28   Crud, Likeable,
29 };
30
31 pub async fn receive_undo(
32   activity: AnyBase,
33   client: &Client,
34   pool: &DbPool,
35   chat_server: ChatServerParam,
36 ) -> Result<HttpResponse, LemmyError> {
37   let undo = Undo::from_any_base(activity)?.unwrap();
38   match undo.object().as_single_kind_str() {
39     Some("Delete") => receive_undo_delete(undo, client, pool, chat_server).await,
40     Some("Remove") => receive_undo_remove(undo, client, pool, chat_server).await,
41     Some("Like") => receive_undo_like(undo, client, pool, chat_server).await,
42     Some("Dislike") => receive_undo_dislike(undo, client, pool, chat_server).await,
43     // TODO: handle undo_dislike?
44     _ => receive_unhandled_activity(undo),
45   }
46 }
47
48 async fn receive_undo_delete(
49   undo: Undo,
50   client: &Client,
51   pool: &DbPool,
52   chat_server: ChatServerParam,
53 ) -> Result<HttpResponse, LemmyError> {
54   let delete = Delete::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
55   let type_ = delete.object().as_single_kind_str().unwrap();
56   match type_ {
57     "Note" => receive_undo_delete_comment(undo, &delete, client, pool, chat_server).await,
58     "Page" => receive_undo_delete_post(undo, &delete, client, pool, chat_server).await,
59     "Group" => receive_undo_delete_community(undo, &delete, client, pool, chat_server).await,
60     d => Err(format_err!("Undo Delete type {} not supported", d).into()),
61   }
62 }
63
64 async fn receive_undo_remove(
65   undo: Undo,
66   client: &Client,
67   pool: &DbPool,
68   chat_server: ChatServerParam,
69 ) -> Result<HttpResponse, LemmyError> {
70   let remove = Remove::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
71
72   let type_ = remove.object().as_single_kind_str().unwrap();
73   match type_ {
74     "Note" => receive_undo_remove_comment(undo, &remove, client, pool, chat_server).await,
75     "Page" => receive_undo_remove_post(undo, &remove, client, pool, chat_server).await,
76     "Group" => receive_undo_remove_community(undo, &remove, client, pool, chat_server).await,
77     d => Err(format_err!("Undo Delete type {} not supported", d).into()),
78   }
79 }
80
81 async fn receive_undo_like(
82   undo: Undo,
83   client: &Client,
84   pool: &DbPool,
85   chat_server: ChatServerParam,
86 ) -> Result<HttpResponse, LemmyError> {
87   let like = Like::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
88
89   let type_ = like.object().as_single_kind_str().unwrap();
90   match type_ {
91     "Note" => receive_undo_like_comment(undo, &like, client, pool, chat_server).await,
92     "Page" => receive_undo_like_post(undo, &like, client, pool, chat_server).await,
93     d => Err(format_err!("Undo Delete type {} not supported", d).into()),
94   }
95 }
96
97 async fn receive_undo_dislike(
98   undo: Undo,
99   _client: &Client,
100   _pool: &DbPool,
101   _chat_server: ChatServerParam,
102 ) -> Result<HttpResponse, LemmyError> {
103   let dislike = Dislike::from_any_base(undo.object().to_owned().one().unwrap())?.unwrap();
104
105   let type_ = dislike.object().as_single_kind_str().unwrap();
106   Err(format_err!("Undo Delete type {} not supported", type_).into())
107 }
108
109 async fn receive_undo_delete_comment(
110   undo: Undo,
111   delete: &Delete,
112   client: &Client,
113   pool: &DbPool,
114   chat_server: ChatServerParam,
115 ) -> Result<HttpResponse, LemmyError> {
116   let user = get_user_from_activity(delete, client, pool).await?;
117   let note = Note::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
118
119   let comment_ap_id = CommentForm::from_apub(&note, client, pool, &user.actor_id()?)
120     .await?
121     .get_ap_id()?;
122
123   let comment = get_or_fetch_and_insert_remote_comment(&comment_ap_id, client, pool).await?;
124
125   let comment_form = CommentForm {
126     content: comment.content.to_owned(),
127     parent_id: comment.parent_id,
128     post_id: comment.post_id,
129     creator_id: comment.creator_id,
130     removed: None,
131     deleted: Some(false),
132     read: None,
133     published: None,
134     updated: Some(naive_now()),
135     ap_id: comment.ap_id,
136     local: comment.local,
137   };
138   let comment_id = comment.id;
139   blocking(pool, move |conn| {
140     Comment::update(conn, comment_id, &comment_form)
141   })
142   .await??;
143
144   // Refetch the view
145   let comment_id = comment.id;
146   let comment_view =
147     blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
148
149   // TODO get those recipient actor ids from somewhere
150   let recipient_ids = vec![];
151   let res = CommentResponse {
152     comment: comment_view,
153     recipient_ids,
154     form_id: None,
155   };
156
157   chat_server.do_send(SendComment {
158     op: UserOperation::EditComment,
159     comment: res,
160     my_id: None,
161   });
162
163   announce_if_community_is_local(undo, &user, client, pool).await?;
164   Ok(HttpResponse::Ok().finish())
165 }
166
167 async fn receive_undo_remove_comment(
168   undo: Undo,
169   remove: &Remove,
170   client: &Client,
171   pool: &DbPool,
172   chat_server: ChatServerParam,
173 ) -> Result<HttpResponse, LemmyError> {
174   let mod_ = get_user_from_activity(remove, client, pool).await?;
175   let note = Note::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
176
177   let comment_ap_id = CommentForm::from_apub(&note, client, pool, &mod_.actor_id()?)
178     .await?
179     .get_ap_id()?;
180
181   let comment = get_or_fetch_and_insert_remote_comment(&comment_ap_id, client, pool).await?;
182
183   let comment_form = CommentForm {
184     content: comment.content.to_owned(),
185     parent_id: comment.parent_id,
186     post_id: comment.post_id,
187     creator_id: comment.creator_id,
188     removed: Some(false),
189     deleted: None,
190     read: None,
191     published: None,
192     updated: Some(naive_now()),
193     ap_id: comment.ap_id,
194     local: comment.local,
195   };
196   let comment_id = comment.id;
197   blocking(pool, move |conn| {
198     Comment::update(conn, comment_id, &comment_form)
199   })
200   .await??;
201
202   // Refetch the view
203   let comment_id = comment.id;
204   let comment_view =
205     blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
206
207   // TODO get those recipient actor ids from somewhere
208   let recipient_ids = vec![];
209   let res = CommentResponse {
210     comment: comment_view,
211     recipient_ids,
212     form_id: None,
213   };
214
215   chat_server.do_send(SendComment {
216     op: UserOperation::EditComment,
217     comment: res,
218     my_id: None,
219   });
220
221   announce_if_community_is_local(undo, &mod_, client, pool).await?;
222   Ok(HttpResponse::Ok().finish())
223 }
224
225 async fn receive_undo_delete_post(
226   undo: Undo,
227   delete: &Delete,
228   client: &Client,
229   pool: &DbPool,
230   chat_server: ChatServerParam,
231 ) -> Result<HttpResponse, LemmyError> {
232   let user = get_user_from_activity(delete, client, pool).await?;
233   let page = PageExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
234
235   let post_ap_id = PostForm::from_apub(&page, client, pool, &user.actor_id()?)
236     .await?
237     .get_ap_id()?;
238
239   let post = get_or_fetch_and_insert_remote_post(&post_ap_id, client, pool).await?;
240
241   let post_form = PostForm {
242     name: post.name.to_owned(),
243     url: post.url.to_owned(),
244     body: post.body.to_owned(),
245     creator_id: post.creator_id.to_owned(),
246     community_id: post.community_id,
247     removed: None,
248     deleted: Some(false),
249     nsfw: post.nsfw,
250     locked: None,
251     stickied: None,
252     updated: Some(naive_now()),
253     embed_title: post.embed_title,
254     embed_description: post.embed_description,
255     embed_html: post.embed_html,
256     thumbnail_url: post.thumbnail_url,
257     ap_id: post.ap_id,
258     local: post.local,
259     published: None,
260   };
261   let post_id = post.id;
262   blocking(pool, move |conn| Post::update(conn, post_id, &post_form)).await??;
263
264   // Refetch the view
265   let post_id = post.id;
266   let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
267
268   let res = PostResponse { post: post_view };
269
270   chat_server.do_send(SendPost {
271     op: UserOperation::EditPost,
272     post: res,
273     my_id: None,
274   });
275
276   announce_if_community_is_local(undo, &user, client, pool).await?;
277   Ok(HttpResponse::Ok().finish())
278 }
279
280 async fn receive_undo_remove_post(
281   undo: Undo,
282   remove: &Remove,
283   client: &Client,
284   pool: &DbPool,
285   chat_server: ChatServerParam,
286 ) -> Result<HttpResponse, LemmyError> {
287   let mod_ = get_user_from_activity(remove, client, pool).await?;
288   let page = PageExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
289
290   let post_ap_id = PostForm::from_apub(&page, client, pool, &mod_.actor_id()?)
291     .await?
292     .get_ap_id()?;
293
294   let post = get_or_fetch_and_insert_remote_post(&post_ap_id, client, pool).await?;
295
296   let post_form = PostForm {
297     name: post.name.to_owned(),
298     url: post.url.to_owned(),
299     body: post.body.to_owned(),
300     creator_id: post.creator_id.to_owned(),
301     community_id: post.community_id,
302     removed: Some(false),
303     deleted: None,
304     nsfw: post.nsfw,
305     locked: None,
306     stickied: None,
307     updated: Some(naive_now()),
308     embed_title: post.embed_title,
309     embed_description: post.embed_description,
310     embed_html: post.embed_html,
311     thumbnail_url: post.thumbnail_url,
312     ap_id: post.ap_id,
313     local: post.local,
314     published: None,
315   };
316   let post_id = post.id;
317   blocking(pool, move |conn| Post::update(conn, post_id, &post_form)).await??;
318
319   // Refetch the view
320   let post_id = post.id;
321   let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
322
323   let res = PostResponse { post: post_view };
324
325   chat_server.do_send(SendPost {
326     op: UserOperation::EditPost,
327     post: res,
328     my_id: None,
329   });
330
331   announce_if_community_is_local(undo, &mod_, client, pool).await?;
332   Ok(HttpResponse::Ok().finish())
333 }
334
335 async fn receive_undo_delete_community(
336   undo: Undo,
337   delete: &Delete,
338   client: &Client,
339   pool: &DbPool,
340   chat_server: ChatServerParam,
341 ) -> Result<HttpResponse, LemmyError> {
342   let user = get_user_from_activity(delete, client, pool).await?;
343   let group = GroupExt::from_any_base(delete.object().to_owned().one().unwrap())?.unwrap();
344
345   let community_actor_id = CommunityForm::from_apub(&group, client, pool, &user.actor_id()?)
346     .await?
347     .actor_id;
348
349   let community = blocking(pool, move |conn| {
350     Community::read_from_actor_id(conn, &community_actor_id)
351   })
352   .await??;
353
354   let community_form = CommunityForm {
355     name: community.name.to_owned(),
356     title: community.title.to_owned(),
357     description: community.description.to_owned(),
358     category_id: community.category_id, // Note: need to keep this due to foreign key constraint
359     creator_id: community.creator_id,   // Note: need to keep this due to foreign key constraint
360     removed: None,
361     published: None,
362     updated: Some(naive_now()),
363     deleted: Some(false),
364     nsfw: community.nsfw,
365     actor_id: community.actor_id,
366     local: community.local,
367     private_key: community.private_key,
368     public_key: community.public_key,
369     last_refreshed_at: None,
370   };
371
372   let community_id = community.id;
373   blocking(pool, move |conn| {
374     Community::update(conn, community_id, &community_form)
375   })
376   .await??;
377
378   let community_id = community.id;
379   let res = CommunityResponse {
380     community: blocking(pool, move |conn| {
381       CommunityView::read(conn, community_id, None)
382     })
383     .await??,
384   };
385
386   let community_id = res.community.id;
387
388   chat_server.do_send(SendCommunityRoomMessage {
389     op: UserOperation::EditCommunity,
390     response: res,
391     community_id,
392     my_id: None,
393   });
394
395   announce_if_community_is_local(undo, &user, client, pool).await?;
396   Ok(HttpResponse::Ok().finish())
397 }
398
399 async fn receive_undo_remove_community(
400   undo: Undo,
401   remove: &Remove,
402   client: &Client,
403   pool: &DbPool,
404   chat_server: ChatServerParam,
405 ) -> Result<HttpResponse, LemmyError> {
406   let mod_ = get_user_from_activity(remove, client, pool).await?;
407   let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
408
409   let community_actor_id = CommunityForm::from_apub(&group, client, pool, &mod_.actor_id()?)
410     .await?
411     .actor_id;
412
413   let community = blocking(pool, move |conn| {
414     Community::read_from_actor_id(conn, &community_actor_id)
415   })
416   .await??;
417
418   let community_form = CommunityForm {
419     name: community.name.to_owned(),
420     title: community.title.to_owned(),
421     description: community.description.to_owned(),
422     category_id: community.category_id, // Note: need to keep this due to foreign key constraint
423     creator_id: community.creator_id,   // Note: need to keep this due to foreign key constraint
424     removed: Some(false),
425     published: None,
426     updated: Some(naive_now()),
427     deleted: None,
428     nsfw: community.nsfw,
429     actor_id: community.actor_id,
430     local: community.local,
431     private_key: community.private_key,
432     public_key: community.public_key,
433     last_refreshed_at: None,
434   };
435
436   let community_id = community.id;
437   blocking(pool, move |conn| {
438     Community::update(conn, community_id, &community_form)
439   })
440   .await??;
441
442   let community_id = community.id;
443   let res = CommunityResponse {
444     community: blocking(pool, move |conn| {
445       CommunityView::read(conn, community_id, None)
446     })
447     .await??,
448   };
449
450   let community_id = res.community.id;
451
452   chat_server.do_send(SendCommunityRoomMessage {
453     op: UserOperation::EditCommunity,
454     response: res,
455     community_id,
456     my_id: None,
457   });
458
459   announce_if_community_is_local(undo, &mod_, client, pool).await?;
460   Ok(HttpResponse::Ok().finish())
461 }
462
463 async fn receive_undo_like_comment(
464   undo: Undo,
465   like: &Like,
466   client: &Client,
467   pool: &DbPool,
468   chat_server: ChatServerParam,
469 ) -> Result<HttpResponse, LemmyError> {
470   let user = get_user_from_activity(like, client, pool).await?;
471   let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
472
473   let comment = CommentForm::from_apub(&note, client, pool, &user.actor_id()?).await?;
474
475   let comment_id = get_or_fetch_and_insert_remote_comment(&comment.get_ap_id()?, client, pool)
476     .await?
477     .id;
478
479   let like_form = CommentLikeForm {
480     comment_id,
481     post_id: comment.post_id,
482     user_id: user.id,
483     score: 0,
484   };
485   blocking(pool, move |conn| CommentLike::remove(conn, &like_form)).await??;
486
487   // Refetch the view
488   let comment_view =
489     blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
490
491   // TODO get those recipient actor ids from somewhere
492   let recipient_ids = vec![];
493   let res = CommentResponse {
494     comment: comment_view,
495     recipient_ids,
496     form_id: None,
497   };
498
499   chat_server.do_send(SendComment {
500     op: UserOperation::CreateCommentLike,
501     comment: res,
502     my_id: None,
503   });
504
505   announce_if_community_is_local(undo, &user, client, pool).await?;
506   Ok(HttpResponse::Ok().finish())
507 }
508
509 async fn receive_undo_like_post(
510   undo: Undo,
511   like: &Like,
512   client: &Client,
513   pool: &DbPool,
514   chat_server: ChatServerParam,
515 ) -> Result<HttpResponse, LemmyError> {
516   let user = get_user_from_activity(like, client, pool).await?;
517   let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
518
519   let post = PostForm::from_apub(&page, client, pool, &user.actor_id()?).await?;
520
521   let post_id = get_or_fetch_and_insert_remote_post(&post.get_ap_id()?, client, pool)
522     .await?
523     .id;
524
525   let like_form = PostLikeForm {
526     post_id,
527     user_id: user.id,
528     score: 1,
529   };
530   blocking(pool, move |conn| PostLike::remove(conn, &like_form)).await??;
531
532   // Refetch the view
533   let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
534
535   let res = PostResponse { post: post_view };
536
537   chat_server.do_send(SendPost {
538     op: UserOperation::CreatePostLike,
539     post: res,
540     my_id: None,
541   });
542
543   announce_if_community_is_local(undo, &user, client, pool).await?;
544   Ok(HttpResponse::Ok().finish())
545 }