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