2 activities::{verify_mod_action, verify_person_in_community},
3 fetcher::object_id::ObjectId,
4 objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
5 protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
7 use lemmy_api_common::blocking;
9 traits::{ActorType, ApubObject},
10 verify::verify_domains_match,
12 use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
13 use lemmy_utils::LemmyError;
14 use lemmy_websocket::{
15 send::{send_comment_ws_message_simple, send_community_ws_message, send_post_ws_message},
24 pub async fn send_apub_delete(
26 community: &ApubCommunity,
29 context: &LemmyContext,
30 ) -> Result<(), LemmyError> {
32 Delete::send(actor, community, object_id, None, context).await
34 UndoDelete::send(actor, community, object_id, None, context).await
38 // TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its
40 pub async fn send_apub_remove(
42 community: &ApubCommunity,
46 context: &LemmyContext,
47 ) -> Result<(), LemmyError> {
49 Delete::send(actor, community, object_id, Some(reason), context).await
51 UndoDelete::send(actor, community, object_id, Some(reason), context).await
55 pub enum DeletableObjects {
56 Community(Box<ApubCommunity>),
57 Comment(Box<ApubComment>),
61 impl DeletableObjects {
62 pub(crate) async fn read_from_db(
64 context: &LemmyContext,
65 ) -> Result<DeletableObjects, LemmyError> {
66 if let Some(c) = ApubCommunity::read_from_apub_id(ap_id.clone(), context).await? {
67 return Ok(DeletableObjects::Community(Box::new(c)));
69 if let Some(p) = ApubPost::read_from_apub_id(ap_id.clone(), context).await? {
70 return Ok(DeletableObjects::Post(Box::new(p)));
72 if let Some(c) = ApubComment::read_from_apub_id(ap_id.clone(), context).await? {
73 return Ok(DeletableObjects::Comment(Box::new(c)));
75 Err(diesel::NotFound.into())
79 pub(in crate::activities) async fn verify_delete_activity(
81 actor: &ObjectId<ApubPerson>,
82 community: &ApubCommunity,
84 context: &LemmyContext,
85 request_counter: &mut i32,
86 ) -> Result<(), LemmyError> {
87 let object = DeletableObjects::read_from_db(object, context).await?;
89 DeletableObjects::Community(community) => {
91 // can only do this check for local community, in remote case it would try to fetch the
92 // deleted community (which fails)
93 verify_person_in_community(actor, &community, context, request_counter).await?;
95 // community deletion is always a mod (or admin) action
96 verify_mod_action(actor, &community, context, request_counter).await?;
98 DeletableObjects::Post(p) => {
99 verify_delete_activity_post_or_comment(
101 &p.ap_id.clone().into(),
109 DeletableObjects::Comment(c) => {
110 verify_delete_activity_post_or_comment(
112 &c.ap_id.clone().into(),
124 async fn verify_delete_activity_post_or_comment(
125 actor: &ObjectId<ApubPerson>,
127 community: &ApubCommunity,
129 context: &LemmyContext,
130 request_counter: &mut i32,
131 ) -> Result<(), LemmyError> {
132 verify_person_in_community(actor, community, context, request_counter).await?;
134 verify_mod_action(actor, community, context, request_counter).await?;
136 // domain of post ap_id and post.creator ap_id are identical, so we just check the former
137 verify_domains_match(actor.inner(), object_id)?;
142 /// Write deletion or restoring of an object to the database, and send websocket message.
143 /// TODO: we should do something similar for receive_remove_action(), but its much more complicated
144 /// because of the mod log
145 async fn receive_delete_action(
147 actor: &ObjectId<ApubPerson>,
149 context: &LemmyContext,
150 request_counter: &mut i32,
151 ) -> Result<(), LemmyError> {
152 match DeletableObjects::read_from_db(object, context).await? {
153 DeletableObjects::Community(community) => {
155 let mod_ = actor.dereference(context, request_counter).await?;
156 let object = community.actor_id();
157 send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
160 let community = blocking(context.pool(), move |conn| {
161 Community::update_deleted(conn, community.id, deleted)
164 send_community_ws_message(
166 UserOperationCrud::DeleteCommunity,
173 DeletableObjects::Post(post) => {
174 if deleted != post.deleted {
175 let deleted_post = blocking(context.pool(), move |conn| {
176 Post::update_deleted(conn, post.id, deleted)
179 send_post_ws_message(
181 UserOperationCrud::DeletePost,
189 DeletableObjects::Comment(comment) => {
190 if deleted != comment.deleted {
191 let deleted_comment = blocking(context.pool(), move |conn| {
192 Comment::update_deleted(conn, comment.id, deleted)
195 send_comment_ws_message_simple(
197 UserOperationCrud::DeleteComment,