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