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