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