]> Untitled Git - lemmy.git/blob - server/src/apub/inbox/activities/undo.rs
Preferred usernames, banners and icons. (#1055)
[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_comment, get_or_fetch_and_insert_post},
5     inbox::shared_inbox::{
6       announce_if_community_is_local,
7       get_user_from_activity,
8       receive_unhandled_activity,
9     },
10     FromApub,
11     GroupExt,
12     PageExt,
13   },
14   blocking,
15   routes::ChatServerParam,
16   websocket::{
17     server::{SendComment, SendCommunityRoomMessage, SendPost},
18     UserOperation,
19   },
20   DbPool,
21   LemmyError,
22 };
23 use activitystreams::{activity::*, base::AnyBase, object::Note, prelude::*};
24 use actix_web::{client::Client, HttpResponse};
25 use anyhow::anyhow;
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(anyhow!("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(anyhow!("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(anyhow!("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(anyhow!("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)
127     .await?
128     .get_ap_id()?;
129
130   let comment = get_or_fetch_and_insert_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)
185     .await?
186     .get_ap_id()?;
187
188   let comment = get_or_fetch_and_insert_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)
243     .await?
244     .get_ap_id()?;
245
246   let post = get_or_fetch_and_insert_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)
298     .await?
299     .get_ap_id()?;
300
301   let post = get_or_fetch_and_insert_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)
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     icon: Some(community.icon.to_owned()),
378     banner: Some(community.banner.to_owned()),
379   };
380
381   let community_id = community.id;
382   blocking(pool, move |conn| {
383     Community::update(conn, community_id, &community_form)
384   })
385   .await??;
386
387   let community_id = community.id;
388   let res = CommunityResponse {
389     community: blocking(pool, move |conn| {
390       CommunityView::read(conn, community_id, None)
391     })
392     .await??,
393   };
394
395   let community_id = res.community.id;
396
397   chat_server.do_send(SendCommunityRoomMessage {
398     op: UserOperation::EditCommunity,
399     response: res,
400     community_id,
401     my_id: None,
402   });
403
404   announce_if_community_is_local(undo, &user, client, pool).await?;
405   Ok(HttpResponse::Ok().finish())
406 }
407
408 async fn receive_undo_remove_community(
409   undo: Undo,
410   remove: &Remove,
411   client: &Client,
412   pool: &DbPool,
413   chat_server: ChatServerParam,
414 ) -> Result<HttpResponse, LemmyError> {
415   let mod_ = get_user_from_activity(remove, client, pool).await?;
416   let group = GroupExt::from_any_base(remove.object().to_owned().one().unwrap())?.unwrap();
417
418   let community_actor_id = CommunityForm::from_apub(&group, client, pool)
419     .await?
420     .actor_id;
421
422   let community = blocking(pool, move |conn| {
423     Community::read_from_actor_id(conn, &community_actor_id)
424   })
425   .await??;
426
427   let community_form = CommunityForm {
428     name: community.name.to_owned(),
429     title: community.title.to_owned(),
430     description: community.description.to_owned(),
431     category_id: community.category_id, // Note: need to keep this due to foreign key constraint
432     creator_id: community.creator_id,   // Note: need to keep this due to foreign key constraint
433     removed: Some(false),
434     published: None,
435     updated: Some(naive_now()),
436     deleted: None,
437     nsfw: community.nsfw,
438     actor_id: community.actor_id,
439     local: community.local,
440     private_key: community.private_key,
441     public_key: community.public_key,
442     last_refreshed_at: None,
443     icon: Some(community.icon.to_owned()),
444     banner: Some(community.banner.to_owned()),
445   };
446
447   let community_id = community.id;
448   blocking(pool, move |conn| {
449     Community::update(conn, community_id, &community_form)
450   })
451   .await??;
452
453   let community_id = community.id;
454   let res = CommunityResponse {
455     community: blocking(pool, move |conn| {
456       CommunityView::read(conn, community_id, None)
457     })
458     .await??,
459   };
460
461   let community_id = res.community.id;
462
463   chat_server.do_send(SendCommunityRoomMessage {
464     op: UserOperation::EditCommunity,
465     response: res,
466     community_id,
467     my_id: None,
468   });
469
470   announce_if_community_is_local(undo, &mod_, client, pool).await?;
471   Ok(HttpResponse::Ok().finish())
472 }
473
474 async fn receive_undo_like_comment(
475   undo: Undo,
476   like: &Like,
477   client: &Client,
478   pool: &DbPool,
479   chat_server: ChatServerParam,
480 ) -> Result<HttpResponse, LemmyError> {
481   let user = get_user_from_activity(like, client, pool).await?;
482   let note = Note::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
483
484   let comment = CommentForm::from_apub(&note, client, pool).await?;
485
486   let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, client, pool)
487     .await?
488     .id;
489
490   let like_form = CommentLikeForm {
491     comment_id,
492     post_id: comment.post_id,
493     user_id: user.id,
494     score: 0,
495   };
496   blocking(pool, move |conn| CommentLike::remove(conn, &like_form)).await??;
497
498   // Refetch the view
499   let comment_view =
500     blocking(pool, move |conn| CommentView::read(conn, comment_id, None)).await??;
501
502   // TODO get those recipient actor ids from somewhere
503   let recipient_ids = vec![];
504   let res = CommentResponse {
505     comment: comment_view,
506     recipient_ids,
507     form_id: None,
508   };
509
510   chat_server.do_send(SendComment {
511     op: UserOperation::CreateCommentLike,
512     comment: res,
513     my_id: None,
514   });
515
516   announce_if_community_is_local(undo, &user, client, pool).await?;
517   Ok(HttpResponse::Ok().finish())
518 }
519
520 async fn receive_undo_like_post(
521   undo: Undo,
522   like: &Like,
523   client: &Client,
524   pool: &DbPool,
525   chat_server: ChatServerParam,
526 ) -> Result<HttpResponse, LemmyError> {
527   let user = get_user_from_activity(like, client, pool).await?;
528   let page = PageExt::from_any_base(like.object().to_owned().one().unwrap())?.unwrap();
529
530   let post = PostForm::from_apub(&page, client, pool).await?;
531
532   let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, client, pool)
533     .await?
534     .id;
535
536   let like_form = PostLikeForm {
537     post_id,
538     user_id: user.id,
539     score: 1,
540   };
541   blocking(pool, move |conn| PostLike::remove(conn, &like_form)).await??;
542
543   // Refetch the view
544   let post_view = blocking(pool, move |conn| PostView::read(conn, post_id, None)).await??;
545
546   let res = PostResponse { post: post_view };
547
548   chat_server.do_send(SendPost {
549     op: UserOperation::CreatePostLike,
550     post: res,
551     my_id: None,
552   });
553
554   announce_if_community_is_local(undo, &user, client, pool).await?;
555   Ok(HttpResponse::Ok().finish())
556 }