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