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