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