]> Untitled Git - lemmy.git/blob - crates/apub/src/activities/deletion/undo_delete.rs
Merge different delete activities for better compatibility (fixes #2066) (#2073)
[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,
9   protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
10 };
11 use activitystreams_kinds::activity::UndoType;
12 use lemmy_api_common::blocking;
13 use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler};
14 use lemmy_db_schema::source::{comment::Comment, community::Community, person::Person, post::Post};
15 use lemmy_utils::LemmyError;
16 use lemmy_websocket::{
17   send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
18   LemmyContext,
19   UserOperationCrud,
20 };
21 use url::Url;
22
23 #[async_trait::async_trait(?Send)]
24 impl ActivityHandler for UndoDelete {
25   type DataType = LemmyContext;
26
27   #[tracing::instrument(skip_all)]
28   async fn verify(
29     &self,
30     context: &Data<LemmyContext>,
31     request_counter: &mut i32,
32   ) -> Result<(), LemmyError> {
33     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
34     self.object.verify(context, request_counter).await?;
35     verify_delete_activity(
36       &self.object,
37       self.object.summary.is_some(),
38       context,
39       request_counter,
40     )
41     .await?;
42     Ok(())
43   }
44
45   #[tracing::instrument(skip_all)]
46   async fn receive(
47     self,
48     context: &Data<LemmyContext>,
49     request_counter: &mut i32,
50   ) -> Result<(), LemmyError> {
51     if self.object.summary.is_some() {
52       UndoDelete::receive_undo_remove_action(self.object.object.id(), context).await
53     } else {
54       receive_delete_action(
55         self.object.object.id(),
56         &self.actor,
57         false,
58         context,
59         request_counter,
60       )
61       .await
62     }
63   }
64 }
65
66 impl UndoDelete {
67   #[tracing::instrument(skip_all)]
68   pub(in crate::activities::deletion) fn new(
69     actor: &Person,
70     object: DeletableObjects,
71     to: Url,
72     community: Option<&Community>,
73     summary: Option<String>,
74     context: &LemmyContext,
75   ) -> Result<UndoDelete, LemmyError> {
76     let object = Delete::new(actor, object, to.clone(), community, summary, context)?;
77
78     let id = generate_activity_id(
79       UndoType::Undo,
80       &context.settings().get_protocol_and_hostname(),
81     )?;
82     let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
83     Ok(UndoDelete {
84       actor: ObjectId::new(actor.actor_id.clone()),
85       to: vec![to],
86       object,
87       cc: cc.into_iter().collect(),
88       kind: UndoType::Undo,
89       id,
90       unparsed: Default::default(),
91     })
92   }
93
94   #[tracing::instrument(skip_all)]
95   pub(in crate::activities) async fn receive_undo_remove_action(
96     object: &Url,
97     context: &LemmyContext,
98   ) -> Result<(), LemmyError> {
99     use UserOperationCrud::*;
100     match DeletableObjects::read_from_db(object, context).await? {
101       DeletableObjects::Community(community) => {
102         if community.local {
103           return Err(LemmyError::from_message(
104             "Only local admin can restore community",
105           ));
106         }
107         let deleted_community = blocking(context.pool(), move |conn| {
108           Community::update_removed(conn, community.id, false)
109         })
110         .await??;
111         send_community_ws_message(deleted_community.id, EditCommunity, None, None, context).await?;
112       }
113       DeletableObjects::Post(post) => {
114         let removed_post = blocking(context.pool(), move |conn| {
115           Post::update_removed(conn, post.id, false)
116         })
117         .await??;
118         send_post_ws_message(removed_post.id, EditPost, None, None, context).await?;
119       }
120       DeletableObjects::Comment(comment) => {
121         let removed_comment = blocking(context.pool(), move |conn| {
122           Comment::update_removed(conn, comment.id, false)
123         })
124         .await??;
125         send_comment_ws_message_simple(removed_comment.id, EditComment, context).await?;
126       }
127       DeletableObjects::PrivateMessage(_) => unimplemented!(),
128     }
129     Ok(())
130   }
131 }
132
133 #[async_trait::async_trait(?Send)]
134 impl GetCommunity for UndoDelete {
135   #[tracing::instrument(skip_all)]
136   async fn get_community(
137     &self,
138     context: &LemmyContext,
139     request_counter: &mut i32,
140   ) -> Result<ApubCommunity, LemmyError> {
141     self.object.get_community(context, request_counter).await
142   }
143 }