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