]> Untitled Git - lemmy.git/blob - src/apub/inbox/activities/remove.rs
Isomorphic docker (#1124)
[lemmy.git] / src / apub / inbox / activities / remove.rs
1 use crate::{
2   apub::{
3     fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
4     inbox::shared_inbox::{
5       announce_if_community_is_local,
6       get_community_id_from_activity,
7       get_user_from_activity,
8       receive_unhandled_activity,
9     },
10     ActorType,
11     FromApub,
12     GroupExt,
13     PageExt,
14   },
15   websocket::{
16     messages::{SendComment, SendCommunityRoomMessage, SendPost},
17     UserOperation,
18   },
19   LemmyContext,
20 };
21 use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*};
22 use actix_web::HttpResponse;
23 use anyhow::{anyhow, Context};
24 use lemmy_api_structs::{
25   blocking,
26   comment::CommentResponse,
27   community::CommunityResponse,
28   post::PostResponse,
29 };
30 use lemmy_db::{
31   comment::{Comment, CommentForm},
32   comment_view::CommentView,
33   community::{Community, CommunityForm},
34   community_view::CommunityView,
35   naive_now,
36   post::{Post, PostForm},
37   post_view::PostView,
38   Crud,
39 };
40 use lemmy_utils::{location_info, LemmyError};
41
42 pub async fn receive_remove(
43   activity: AnyBase,
44   context: &LemmyContext,
45 ) -> Result<HttpResponse, LemmyError> {
46   let remove = Remove::from_any_base(activity)?.context(location_info!())?;
47   let actor = get_user_from_activity(&remove, context).await?;
48   let community = get_community_id_from_activity(&remove)?;
49   if actor.actor_id()?.domain() != community.domain() {
50     return Err(anyhow!("Remove activities are only allowed on local objects").into());
51   }
52
53   match remove.object().as_single_kind_str() {
54     Some("Page") => receive_remove_post(remove, context).await,
55     Some("Note") => receive_remove_comment(remove, context).await,
56     Some("Group") => receive_remove_community(remove, context).await,
57     _ => receive_unhandled_activity(remove),
58   }
59 }
60
61 async fn receive_remove_post(
62   remove: Remove,
63   context: &LemmyContext,
64 ) -> Result<HttpResponse, LemmyError> {
65   let mod_ = get_user_from_activity(&remove, context).await?;
66   let page = PageExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
67     .context(location_info!())?;
68
69   let post_ap_id = PostForm::from_apub(&page, context, None)
70     .await?
71     .get_ap_id()?;
72
73   let post = get_or_fetch_and_insert_post(&post_ap_id, context).await?;
74
75   let post_form = PostForm {
76     name: post.name.to_owned(),
77     url: post.url.to_owned(),
78     body: post.body.to_owned(),
79     creator_id: post.creator_id.to_owned(),
80     community_id: post.community_id,
81     removed: Some(true),
82     deleted: None,
83     nsfw: post.nsfw,
84     locked: None,
85     stickied: None,
86     updated: Some(naive_now()),
87     embed_title: post.embed_title,
88     embed_description: post.embed_description,
89     embed_html: post.embed_html,
90     thumbnail_url: post.thumbnail_url,
91     ap_id: Some(post.ap_id),
92     local: post.local,
93     published: None,
94   };
95   let post_id = post.id;
96   blocking(context.pool(), move |conn| {
97     Post::update(conn, post_id, &post_form)
98   })
99   .await??;
100
101   // Refetch the view
102   let post_id = post.id;
103   let post_view = blocking(context.pool(), move |conn| {
104     PostView::read(conn, post_id, None)
105   })
106   .await??;
107
108   let res = PostResponse { post: post_view };
109
110   context.chat_server().do_send(SendPost {
111     op: UserOperation::EditPost,
112     post: res,
113     websocket_id: None,
114   });
115
116   announce_if_community_is_local(remove, &mod_, context).await?;
117   Ok(HttpResponse::Ok().finish())
118 }
119
120 async fn receive_remove_comment(
121   remove: Remove,
122   context: &LemmyContext,
123 ) -> Result<HttpResponse, LemmyError> {
124   let mod_ = get_user_from_activity(&remove, context).await?;
125   let note = Note::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
126     .context(location_info!())?;
127
128   let comment_ap_id = CommentForm::from_apub(&note, context, None)
129     .await?
130     .get_ap_id()?;
131
132   let comment = get_or_fetch_and_insert_comment(&comment_ap_id, context).await?;
133
134   let comment_form = CommentForm {
135     content: comment.content.to_owned(),
136     parent_id: comment.parent_id,
137     post_id: comment.post_id,
138     creator_id: comment.creator_id,
139     removed: Some(true),
140     deleted: None,
141     read: None,
142     published: None,
143     updated: Some(naive_now()),
144     ap_id: Some(comment.ap_id),
145     local: comment.local,
146   };
147   let comment_id = comment.id;
148   blocking(context.pool(), move |conn| {
149     Comment::update(conn, comment_id, &comment_form)
150   })
151   .await??;
152
153   // Refetch the view
154   let comment_id = comment.id;
155   let comment_view = blocking(context.pool(), move |conn| {
156     CommentView::read(conn, comment_id, None)
157   })
158   .await??;
159
160   // TODO get those recipient actor ids from somewhere
161   let recipient_ids = vec![];
162   let res = CommentResponse {
163     comment: comment_view,
164     recipient_ids,
165     form_id: None,
166   };
167
168   context.chat_server().do_send(SendComment {
169     op: UserOperation::EditComment,
170     comment: res,
171     websocket_id: None,
172   });
173
174   announce_if_community_is_local(remove, &mod_, context).await?;
175   Ok(HttpResponse::Ok().finish())
176 }
177
178 async fn receive_remove_community(
179   remove: Remove,
180   context: &LemmyContext,
181 ) -> Result<HttpResponse, LemmyError> {
182   let mod_ = get_user_from_activity(&remove, context).await?;
183   let group = GroupExt::from_any_base(remove.object().to_owned().one().context(location_info!())?)?
184     .context(location_info!())?;
185
186   let community_actor_id = CommunityForm::from_apub(&group, context, Some(mod_.actor_id()?))
187     .await?
188     .actor_id
189     .context(location_info!())?;
190
191   let community = blocking(context.pool(), move |conn| {
192     Community::read_from_actor_id(conn, &community_actor_id)
193   })
194   .await??;
195
196   let community_form = CommunityForm {
197     name: community.name.to_owned(),
198     title: community.title.to_owned(),
199     description: community.description.to_owned(),
200     category_id: community.category_id, // Note: need to keep this due to foreign key constraint
201     creator_id: community.creator_id,   // Note: need to keep this due to foreign key constraint
202     removed: Some(true),
203     published: None,
204     updated: Some(naive_now()),
205     deleted: None,
206     nsfw: community.nsfw,
207     actor_id: Some(community.actor_id),
208     local: community.local,
209     private_key: community.private_key,
210     public_key: community.public_key,
211     last_refreshed_at: None,
212     icon: Some(community.icon.to_owned()),
213     banner: Some(community.banner.to_owned()),
214   };
215
216   let community_id = community.id;
217   blocking(context.pool(), move |conn| {
218     Community::update(conn, community_id, &community_form)
219   })
220   .await??;
221
222   let community_id = community.id;
223   let res = CommunityResponse {
224     community: blocking(context.pool(), move |conn| {
225       CommunityView::read(conn, community_id, None)
226     })
227     .await??,
228   };
229
230   let community_id = res.community.id;
231
232   context.chat_server().do_send(SendCommunityRoomMessage {
233     op: UserOperation::EditCommunity,
234     response: res,
235     community_id,
236     websocket_id: None,
237   });
238
239   announce_if_community_is_local(remove, &mod_, context).await?;
240   Ok(HttpResponse::Ok().finish())
241 }