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