Support mastodon deletes
authorAode (lion) <asonix@asonix.dog>
Tue, 16 Nov 2021 00:58:15 +0000 (18:58 -0600)
committerFelix Ableitner <me@nutomic.com>
Tue, 16 Nov 2021 17:07:47 +0000 (18:07 +0100)
17 files changed:
crates/api_crud/src/comment/delete.rs
crates/api_crud/src/community/delete.rs
crates/api_crud/src/post/delete.rs
crates/apub/assets/lemmy/activities/deletion/delete_page.json
crates/apub/assets/lemmy/activities/deletion/remove_note.json
crates/apub/assets/lemmy/activities/deletion/undo_delete_page.json
crates/apub/assets/lemmy/activities/deletion/undo_remove_note.json
crates/apub/src/activities/deletion/delete.rs
crates/apub/src/activities/deletion/mod.rs
crates/apub/src/activities/deletion/undo_delete.rs
crates/apub/src/activities/mod.rs
crates/apub/src/objects/comment.rs
crates/apub/src/objects/community.rs
crates/apub/src/objects/post.rs
crates/apub/src/protocol/activities/deletion/delete.rs
crates/apub/src/protocol/activities/deletion/mod.rs
crates/apub/src/protocol/objects/tombstone.rs

index f55119f72a9812fefef4ebed32bfedb65ad71dc9..7e920882c19b91a2c75c2da72fc791108bf22f5f 100644 (file)
@@ -7,7 +7,7 @@ use lemmy_api_common::{
   get_local_user_view_from_jwt,
   is_mod_or_admin,
 };
-use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
 use lemmy_db_schema::{
   source::{
     comment::Comment,
@@ -69,6 +69,18 @@ impl PerformCrud for DeleteComment {
     .await?
     .map_err(|e| ApiError::err("couldnt_update_comment", e))?;
 
+    let post_id = updated_comment.post_id;
+    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let recipient_ids = send_local_notifs(
+      vec![],
+      &updated_comment,
+      &local_user_view.person,
+      &post,
+      false,
+      context,
+    )
+    .await?;
+
     // Send the apub message
     let community = blocking(context.pool(), move |conn| {
       Community::read(conn, orig_comment.post.community_id)
@@ -77,24 +89,12 @@ impl PerformCrud for DeleteComment {
     send_apub_delete(
       &local_user_view.person.clone().into(),
       &community.clone().into(),
-      updated_comment.ap_id.clone().into(),
+      DeletableObjects::Comment(Box::new(updated_comment.into())),
       deleted,
       context,
     )
     .await?;
 
-    let post_id = updated_comment.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-    let recipient_ids = send_local_notifs(
-      vec![],
-      &updated_comment,
-      &local_user_view.person,
-      &post,
-      false,
-      context,
-    )
-    .await?;
-
     send_comment_ws_message(
       data.comment_id,
       UserOperationCrud::DeleteComment,
@@ -162,6 +162,18 @@ impl PerformCrud for RemoveComment {
     })
     .await??;
 
+    let post_id = updated_comment.post_id;
+    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+    let recipient_ids = send_local_notifs(
+      vec![],
+      &updated_comment,
+      &local_user_view.person.clone(),
+      &post,
+      false,
+      context,
+    )
+    .await?;
+
     // Send the apub message
     let community = blocking(context.pool(), move |conn| {
       Community::read(conn, orig_comment.post.community_id)
@@ -170,25 +182,13 @@ impl PerformCrud for RemoveComment {
     send_apub_remove(
       &local_user_view.person.clone().into(),
       &community.into(),
-      updated_comment.ap_id.clone().into(),
+      DeletableObjects::Comment(Box::new(updated_comment.into())),
       data.reason.clone().unwrap_or_else(|| "".to_string()),
       removed,
       context,
     )
     .await?;
 
-    let post_id = updated_comment.post_id;
-    let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-    let recipient_ids = send_local_notifs(
-      vec![],
-      &updated_comment,
-      &local_user_view.person.clone(),
-      &post,
-      false,
-      context,
-    )
-    .await?;
-
     send_comment_ws_message(
       data.comment_id,
       UserOperationCrud::RemoveComment,
index bf59e786f721969ca770dcf1b128a939cbf276f7..aec451926ae53f5628e8516644c5da5c740df2f1 100644 (file)
@@ -1,7 +1,7 @@
 use crate::PerformCrud;
 use actix_web::web::Data;
 use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
-use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
 use lemmy_db_schema::{
   source::{
     community::Community,
@@ -51,7 +51,7 @@ impl PerformCrud for DeleteCommunity {
     send_apub_delete(
       &local_user_view.person.clone().into(),
       &updated_community.clone().into(),
-      updated_community.actor_id.clone().into(),
+      DeletableObjects::Community(Box::new(updated_community.into())),
       deleted,
       context,
     )
@@ -111,7 +111,7 @@ impl PerformCrud for RemoveCommunity {
     send_apub_remove(
       &local_user_view.person.clone().into(),
       &updated_community.clone().into(),
-      updated_community.actor_id.clone().into(),
+      DeletableObjects::Community(Box::new(updated_community.into())),
       data.reason.clone().unwrap_or_else(|| "".to_string()),
       removed,
       context,
index af69993480b5e6f2e3b46d77510c6bc8fc9f1462..a974feb12083596eef64121b3a685e10f456d2aa 100644 (file)
@@ -8,7 +8,7 @@ use lemmy_api_common::{
   is_mod_or_admin,
   post::*,
 };
-use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove};
+use lemmy_apub::activities::deletion::{send_apub_delete, send_apub_remove, DeletableObjects};
 use lemmy_db_schema::{
   source::{
     community::Community,
@@ -70,7 +70,7 @@ impl PerformCrud for DeletePost {
     send_apub_delete(
       &local_user_view.person.clone().into(),
       &community.into(),
-      updated_post.ap_id.into(),
+      DeletableObjects::Post(Box::new(updated_post.into())),
       deleted,
       context,
     )
@@ -146,7 +146,7 @@ impl PerformCrud for RemovePost {
     send_apub_remove(
       &local_user_view.person.clone().into(),
       &community.into(),
-      updated_post.ap_id.into(),
+      DeletableObjects::Post(Box::new(updated_post.into())),
       data.reason.clone().unwrap_or_else(|| "".to_string()),
       removed,
       context,
index 8dd26a109ebe48cf7d32b7119ae0bf70327beaf8..6b2aba37c0ab13c2f6c487cb82bd3e4c3f43d728 100644 (file)
@@ -3,7 +3,10 @@
   "to": [
     "https://www.w3.org/ns/activitystreams#Public"
   ],
-  "object": "http://ds9.lemmy.ml/post/1",
+  "object": {
+    "id": "http://ds9.lemmy.ml/post/1",
+    "type": "Tombstone"
+  },
   "cc": [
     "http://enterprise.lemmy.ml/c/main"
   ],
index 8ea354044f84487143ea8859dc2df3399dc95779..07ca4e5cf7d4f8c26bee5704c8e20a5a0655098f 100644 (file)
@@ -3,7 +3,10 @@
   "to": [
     "https://www.w3.org/ns/activitystreams#Public"
   ],
-  "object": "http://ds9.lemmy.ml/comment/1",
+  "object": {
+    "id": "http://ds9.lemmy.ml/comment/1",
+    "type": "Tombstone"
+  },
   "cc": [
     "http://enterprise.lemmy.ml/c/main"
   ],
index 9f824fa1f8f0fb60610ac85385fffcee4ee3197c..d2d5533f0fa3f80bf8e1ccc56f24dda85112d1c5 100644 (file)
@@ -8,7 +8,10 @@
     "to": [
       "https://www.w3.org/ns/activitystreams#Public"
     ],
-    "object": "http://ds9.lemmy.ml/post/1",
+    "object": {
+      "id": "http://ds9.lemmy.ml/post/1",
+      "type": "Tombstone"
+    },
     "cc": [
       "http://enterprise.lemmy.ml/c/main"
     ],
index 413cf16b4e4e605eb94aebaf0ffa8331489a8592..e4c9ee26fbd9bec56a8e7abdede58d15c610ca86 100644 (file)
@@ -8,7 +8,10 @@
     "to": [
       "https://www.w3.org/ns/activitystreams#Public"
     ],
-    "object": "http://ds9.lemmy.ml/comment/1",
+    "object": {
+      "id": "http://ds9.lemmy.ml/comment/1",
+      "type": "Tombstone"
+    },
     "cc": [
       "http://enterprise.lemmy.ml/c/main"
     ],
index cec8ab9a3c543dedf6fd8bf000b5a138ef0bbd11..b976a1b4614ce09611003fa967dc48d988837e48 100644 (file)
@@ -50,11 +50,11 @@ impl ActivityHandler for Delete {
     context: &Data<LemmyContext>,
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
-    verify_is_public(&self.to, &self.cc)?;
+    verify_is_public(&self.to, &[])?;
     verify_activity(&self.id, self.actor.inner(), &context.settings())?;
     let community = self.get_community(context, request_counter).await?;
     verify_delete_activity(
-      &self.object,
+      &self.object.id,
       &self.actor,
       &community,
       self.summary.is_some(),
@@ -78,9 +78,16 @@ impl ActivityHandler for Delete {
       } else {
         Some(reason)
       };
-      receive_remove_action(&self.actor, &self.object, reason, context, request_counter).await
+      receive_remove_action(
+        &self.actor,
+        &self.object.id,
+        reason,
+        context,
+        request_counter,
+      )
+      .await
     } else {
-      receive_delete_action(&self.object, &self.actor, true, context, request_counter).await
+      receive_delete_action(&self.object.id, &self.actor, true, context, request_counter).await
     }
   }
 }
@@ -88,16 +95,14 @@ impl ActivityHandler for Delete {
 impl Delete {
   pub(in crate::activities::deletion) fn new(
     actor: &ApubPerson,
-    community: &ApubCommunity,
-    object_id: Url,
+    object: DeletableObjects,
     summary: Option<String>,
     context: &LemmyContext,
   ) -> Result<Delete, LemmyError> {
     Ok(Delete {
       actor: ObjectId::new(actor.actor_id()),
       to: vec![public()],
-      object: object_id,
-      cc: vec![community.actor_id()],
+      object: object.to_tombstone()?,
       kind: DeleteType::Delete,
       summary,
       id: generate_activity_id(
@@ -110,11 +115,11 @@ impl Delete {
   pub(in crate::activities::deletion) async fn send(
     actor: &ApubPerson,
     community: &ApubCommunity,
-    object_id: Url,
+    object: DeletableObjects,
     summary: Option<String>,
     context: &LemmyContext,
   ) -> Result<(), LemmyError> {
-    let delete = Delete::new(actor, community, object_id, summary, context)?;
+    let delete = Delete::new(actor, object, summary, context)?;
     let delete_id = delete.id.clone();
 
     let activity = AnnouncableActivities::Delete(delete);
@@ -201,7 +206,7 @@ impl GetCommunity for Delete {
     context: &LemmyContext,
     _request_counter: &mut i32,
   ) -> Result<ApubCommunity, LemmyError> {
-    let community_id = match DeletableObjects::read_from_db(&self.object, context).await? {
+    let community_id = match DeletableObjects::read_from_db(&self.object.id, context).await? {
       DeletableObjects::Community(c) => c.id,
       DeletableObjects::Comment(c) => {
         let post = blocking(context.pool(), move |conn| Post::read(conn, c.post_id)).await??;
index ddd607a7c1128618f37b8abd79ec585367a140fb..ab2e7a0bac93680b8695454f6316fd9a3fc2a7fd 100644 (file)
@@ -1,14 +1,13 @@
 use crate::{
   activities::{verify_mod_action, verify_person_in_community},
   objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
-  protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
+  protocol::{
+    activities::deletion::{delete::Delete, undo_delete::UndoDelete},
+    objects::tombstone::Tombstone,
+  },
 };
 use lemmy_api_common::blocking;
-use lemmy_apub_lib::{
-  object_id::ObjectId,
-  traits::{ActorType, ApubObject},
-  verify::verify_domains_match,
-};
+use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject, verify::verify_domains_match};
 use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post};
 use lemmy_utils::LemmyError;
 use lemmy_websocket::{
@@ -24,14 +23,14 @@ pub mod undo_delete;
 pub async fn send_apub_delete(
   actor: &ApubPerson,
   community: &ApubCommunity,
-  object_id: Url,
+  object: DeletableObjects,
   deleted: bool,
   context: &LemmyContext,
 ) -> Result<(), LemmyError> {
   if deleted {
-    Delete::send(actor, community, object_id, None, context).await
+    Delete::send(actor, community, object, None, context).await
   } else {
-    UndoDelete::send(actor, community, object_id, None, context).await
+    UndoDelete::send(actor, community, object, None, context).await
   }
 }
 
@@ -40,15 +39,15 @@ pub async fn send_apub_delete(
 pub async fn send_apub_remove(
   actor: &ApubPerson,
   community: &ApubCommunity,
-  object_id: Url,
+  object: DeletableObjects,
   reason: String,
   removed: bool,
   context: &LemmyContext,
 ) -> Result<(), LemmyError> {
   if removed {
-    Delete::send(actor, community, object_id, Some(reason), context).await
+    Delete::send(actor, community, object, Some(reason), context).await
   } else {
-    UndoDelete::send(actor, community, object_id, Some(reason), context).await
+    UndoDelete::send(actor, community, object, Some(reason), context).await
   }
 }
 
@@ -74,6 +73,14 @@ impl DeletableObjects {
     }
     Err(diesel::NotFound.into())
   }
+
+  pub(crate) fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
+    match self {
+      DeletableObjects::Community(c) => c.to_tombstone(),
+      DeletableObjects::Comment(c) => c.to_tombstone(),
+      DeletableObjects::Post(p) => p.to_tombstone(),
+    }
+  }
 }
 
 pub(in crate::activities) async fn verify_delete_activity(
@@ -153,7 +160,7 @@ async fn receive_delete_action(
     DeletableObjects::Community(community) => {
       if community.local {
         let mod_ = actor.dereference(context, request_counter).await?;
-        let object = community.actor_id();
+        let object = DeletableObjects::Community(community.clone());
         send_apub_delete(&mod_, &community.clone(), object, true, context).await?;
       }
 
index c6e5ddfc0b7e518ca5bb76b2d66b8ab7bf7aef03..28ad0f5a345f814e5456c700dc6654e13b576091 100644 (file)
@@ -40,7 +40,7 @@ impl ActivityHandler for UndoDelete {
     self.object.verify(context, request_counter).await?;
     let community = self.get_community(context, request_counter).await?;
     verify_delete_activity(
-      &self.object.object,
+      &self.object.object.id,
       &self.actor,
       &community,
       self.object.summary.is_some(),
@@ -57,10 +57,10 @@ impl ActivityHandler for UndoDelete {
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
     if self.object.summary.is_some() {
-      UndoDelete::receive_undo_remove_action(&self.object.object, context).await
+      UndoDelete::receive_undo_remove_action(&self.object.object.id, context).await
     } else {
       receive_delete_action(
-        &self.object.object,
+        &self.object.object.id,
         &self.actor,
         false,
         context,
@@ -75,11 +75,11 @@ impl UndoDelete {
   pub(in crate::activities::deletion) async fn send(
     actor: &ApubPerson,
     community: &ApubCommunity,
-    object_id: Url,
+    object: DeletableObjects,
     summary: Option<String>,
     context: &LemmyContext,
   ) -> Result<(), LemmyError> {
-    let object = Delete::new(actor, community, object_id, summary, context)?;
+    let object = Delete::new(actor, object, summary, context)?;
 
     let id = generate_activity_id(
       UndoType::Undo,
index b75d37e457b7622a3d1474770a6828aebb6e4af3..cac5d6e1e863b2ebe1237bc9df2e92cd0032cd74 100644 (file)
@@ -117,7 +117,7 @@ fn verify_add_remove_moderator_target(
 }
 
 pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> {
-  if !to.contains(&public()) && !cc.contains(&public()) {
+  if ![to, cc].iter().any(|set| set.contains(&public())) {
     return Err(anyhow!("Object is not public").into());
   }
   Ok(())
index 406838181c0cb96967f3a275ece67ec1db505249..a3840e10a51da66cf49418f40b7cfd4deb6d2c46 100644 (file)
@@ -132,10 +132,7 @@ impl ApubObject for ApubComment {
   }
 
   fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
-    Ok(Tombstone::new(
-      NoteType::Note,
-      self.updated.unwrap_or(self.published),
-    ))
+    Ok(Tombstone::new(self.ap_id.clone().into()))
   }
 
   async fn verify(
index 87fca8d3504a350bae14ac02e398010245e4864d..f37d82d8cd3a539a475edff5f484d69669336751 100644 (file)
@@ -118,10 +118,7 @@ impl ApubObject for ApubCommunity {
   }
 
   fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
-    Ok(Tombstone::new(
-      GroupType::Group,
-      self.updated.unwrap_or(self.published),
-    ))
+    Ok(Tombstone::new(self.actor_id()))
   }
 
   async fn verify(
index 4e34fc88e73f3c672c00905c910cfdd3b0eaaa2e..44dbe73bd5c1dcf1df96e147b6ea654b5466f949 100644 (file)
@@ -128,10 +128,7 @@ impl ApubObject for ApubPost {
   }
 
   fn to_tombstone(&self) -> Result<Tombstone, LemmyError> {
-    Ok(Tombstone::new(
-      PageType::Page,
-      self.updated.unwrap_or(self.published),
-    ))
+    Ok(Tombstone::new(self.ap_id.clone().into()))
   }
 
   async fn verify(
index 7e2275153f23a51ee2661c083b5798f0e567a628..26aee276e83b25416b40efdc9f29cf4a494e12cb 100644 (file)
@@ -1,4 +1,4 @@
-use crate::objects::person::ApubPerson;
+use crate::{objects::person::ApubPerson, protocol::objects::tombstone::Tombstone};
 use activitystreams::{activity::kind::DeleteType, unparsed::Unparsed};
 use lemmy_apub_lib::object_id::ObjectId;
 use serde::{Deserialize, Serialize};
@@ -11,8 +11,7 @@ use url::Url;
 pub struct Delete {
   pub(crate) actor: ObjectId<ApubPerson>,
   pub(crate) to: Vec<Url>,
-  pub(crate) object: Url,
-  pub(crate) cc: Vec<Url>,
+  pub(crate) object: Tombstone,
   #[serde(rename = "type")]
   pub(crate) kind: DeleteType,
   /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
index c77492a3233f4d13d387106ce895da298de1a8f4..647c3d50708b4f43486ece45f286115073716052 100644 (file)
@@ -11,7 +11,7 @@ mod tests {
 
   #[actix_rt::test]
   #[serial]
-  async fn test_parse_lemmy_voting() {
+  async fn test_parse_lemmy_deletion() {
     test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/remove_note.json");
     test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_page.json");
 
index 2746c5ae600c3f0f89b2c0290440308d07c31e67..152066cb55c5e905c7d4730337940946f1c18827 100644 (file)
@@ -1,25 +1,22 @@
 use activitystreams::object::kind::TombstoneType;
-use chrono::{DateTime, FixedOffset, NaiveDateTime};
-use lemmy_utils::utils::convert_datetime;
 use serde::{Deserialize, Serialize};
 use serde_with::skip_serializing_none;
+use url::Url;
 
 #[skip_serializing_none]
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct Tombstone {
+  pub(crate) id: Url,
   #[serde(rename = "type")]
   kind: TombstoneType,
-  former_type: String,
-  deleted: DateTime<FixedOffset>,
 }
 
 impl Tombstone {
-  pub fn new<T: ToString>(former_type: T, updated_time: NaiveDateTime) -> Tombstone {
+  pub fn new(id: Url) -> Tombstone {
     Tombstone {
+      id,
       kind: TombstoneType::Tombstone,
-      former_type: former_type.to_string(),
-      deleted: convert_datetime(updated_time),
     }
   }
 }