]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Add diesel_async, get rid of blocking function (#2510)
[lemmy.git] / crates / apub / src / activities / deletion / undo_delete.rs
1 use crate::{
2   activities::{
3     community::announce::GetCommunity,
4     deletion::{receive_delete_action, verify_delete_activity, DeletableObjects},
5     generate_activity_id,
6   },
7   local_instance,
8   objects::{community::ApubCommunity, person::ApubPerson},
9   protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
10 };
11 use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler};
12 use activitystreams_kinds::activity::UndoType;
13 use lemmy_db_schema::{
14   source::{
15     comment::{Comment, CommentUpdateForm},
16     community::{Community, CommunityUpdateForm},
17     moderator::{
18       ModRemoveComment,
19       ModRemoveCommentForm,
20       ModRemoveCommunity,
21       ModRemoveCommunityForm,
22       ModRemovePost,
23       ModRemovePostForm,
24     },
25     post::{Post, PostUpdateForm},
26   },
27   traits::Crud,
28 };
29 use lemmy_utils::error::LemmyError;
30 use lemmy_websocket::{
31   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
32   LemmyContext,
33   UserOperationCrud,
34 };
35 use url::Url;
36
37 #[async_trait::async_trait(?Send)]
38 impl ActivityHandler for UndoDelete {
39   type DataType = LemmyContext;
40   type Error = LemmyError;
41
42   fn id(&self) -> &Url {
43     &self.id
44   }
45
46   fn actor(&self) -> &Url {
47     self.actor.inner()
48   }
49
50   #[tracing::instrument(skip_all)]
51   async fn verify(
52     &self,
53     context: &Data<LemmyContext>,
54     request_counter: &mut i32,
55   ) -> Result<(), LemmyError> {
56     self.object.verify(context, request_counter).await?;
57     verify_delete_activity(
58       &self.object,
59       self.object.summary.is_some(),
60       context,
61       request_counter,
62     )
63     .await?;
64     Ok(())
65   }
66
67   #[tracing::instrument(skip_all)]
68   async fn receive(
69     self,
70     context: &Data<LemmyContext>,
71     request_counter: &mut i32,
72   ) -> Result<(), LemmyError> {
73     if self.object.summary.is_some() {
74       UndoDelete::receive_undo_remove_action(
75         &self
76           .actor
77           .dereference(context, local_instance(context).await, request_counter)
78           .await?,
79         self.object.object.id(),
80         context,
81       )
82       .await
83     } else {
84       receive_delete_action(
85         self.object.object.id(),
86         &self.actor,
87         false,
88         context,
89         request_counter,
90       )
91       .await
92     }
93   }
94 }
95
96 impl UndoDelete {
97   #[tracing::instrument(skip_all)]
98   pub(in crate::activities::deletion) fn new(
99     actor: &ApubPerson,
100     object: DeletableObjects,
101     to: Url,
102     community: Option<&Community>,
103     summary: Option<String>,
104     context: &LemmyContext,
105   ) -> Result<UndoDelete, LemmyError> {
106     let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
107
108     let id = generate_activity_id(
109       UndoType::Undo,
110       &context.settings().get_protocol_and_hostname(),
111     )?;
112     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
113     Ok(UndoDelete {
114       actor: ObjectId::new(actor.actor_id.clone()),
115       to: vec![to],
116       object,
117       cc: cc.into_iter().collect(),
118       kind: UndoType::Undo,
119       id,
120       unparsed: Default::default(),
121     })
122   }
123
124   #[tracing::instrument(skip_all)]
125   pub(in crate::activities) async fn receive_undo_remove_action(
126     actor: &ApubPerson,
127     object: &Url,
128     context: &LemmyContext,
129   ) -> Result<(), LemmyError> {
130     use UserOperationCrud::*;
131     match DeletableObjects::read_from_db(object, context).await? {
132       DeletableObjects::Community(community) => {
133         if community.local {
134           return Err(LemmyError::from_message(
135             "Only local admin can restore community",
136           ));
137         }
138         let form = ModRemoveCommunityForm {
139           mod_person_id: actor.id,
140           community_id: community.id,
141           removed: Some(false),
142           reason: None,
143           expires: None,
144         };
145         ModRemoveCommunity::create(context.pool(), &form).await?;
146         let deleted_community = Community::update(
147           context.pool(),
148           community.id,
149           &CommunityUpdateForm::builder().removed(Some(false)).build(),
150         )
151         .await?;
152         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
153       }
154       DeletableObjects::Post(post) => {
155         let form = ModRemovePostForm {
156           mod_person_id: actor.id,
157           post_id: post.id,
158           removed: Some(false),
159           reason: None,
160         };
161         ModRemovePost::create(context.pool(), &form).await?;
162         let removed_post = Post::update(
163           context.pool(),
164           post.id,
165           &PostUpdateForm::builder().removed(Some(false)).build(),
166         )
167         .await?;
168         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
169       }
170       DeletableObjects::Comment(comment) => {
171         let form = ModRemoveCommentForm {
172           mod_person_id: actor.id,
173           comment_id: comment.id,
174           removed: Some(false),
175           reason: None,
176         };
177         ModRemoveComment::create(context.pool(), &form).await?;
178         let removed_comment = Comment::update(
179           context.pool(),
180           comment.id,
181           &CommentUpdateForm::builder().removed(Some(false)).build(),
182         )
183         .await?;
184         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
185       }
186       DeletableObjects::PrivateMessage(_) => unimplemented!(),
187     }
188     Ok(())
189   }
190 }
191
192 #[async_trait::async_trait(?Send)]
193 impl GetCommunity for UndoDelete {
194   #[tracing::instrument(skip_all)]
195   async fn get_community(
196     &self,
197     context: &LemmyContext,
198     request_counter: &mut i32,
199   ) -> Result<ApubCommunity, LemmyError> {
200     self.object.get_community(context, request_counter).await
201   }
202 }