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