]> Untitled Git - lemmy.git/commitdiff
Address comments, implement delete for posts and comments
authorFelix <me@nutomic.com>
Wed, 29 Apr 2020 14:51:25 +0000 (16:51 +0200)
committerFelix <me@nutomic.com>
Wed, 29 Apr 2020 14:51:25 +0000 (16:51 +0200)
server/src/api/comment.rs
server/src/api/community.rs
server/src/api/post.rs
server/src/apub/comment.rs
server/src/apub/community.rs
server/src/apub/mod.rs
server/src/apub/post.rs
server/src/apub/shared_inbox.rs
server/src/apub/user.rs

index a6742e4c027d66fdc3a189caf4e8a9fb27d19895..17b52d2f54d73ef7c996f535cdde3af75efec32d 100644 (file)
@@ -339,6 +339,14 @@ impl Perform for Oper<EditComment> {
 
     updated_comment.send_update(&user, &conn)?;
 
+    if let Some(deleted) = data.deleted.to_owned() {
+      if deleted {
+        updated_comment.send_delete(&user, &conn)?;
+      } else {
+        // TODO: undo delete
+      }
+    }
+
     let mut recipient_ids = Vec::new();
 
     // Scan the comment for user mentions, add those rows
index 7610d1b7847b1dd86cb36b42f272d70702035e82..d7f16c50c27223affd7a069fb9918530ea2ce7dc 100644 (file)
@@ -377,11 +377,14 @@ impl Perform for Oper<EditCommunity> {
         expires,
       };
       ModRemoveCommunity::create(&conn, &form)?;
-      updated_community.send_delete(&conn)?;
     }
 
-    if let Some(_deleted) = data.deleted.to_owned() {
-      updated_community.send_delete(&conn)?;
+    if let Some(deleted) = data.deleted.to_owned() {
+      if deleted {
+        updated_community.send_delete(&conn)?;
+      } else {
+        // TODO: undo delete
+      }
     }
 
     let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
index 306365facfa6b9dd8b6209db9f8069bb7fc2cdcc..56c1337373c524fc0602941145740b4b6bcb136e 100644 (file)
@@ -543,6 +543,14 @@ impl Perform for Oper<EditPost> {
 
     updated_post.send_update(&user, &conn)?;
 
+    if let Some(deleted) = data.deleted.to_owned() {
+      if deleted {
+        updated_post.send_delete(&user, &conn)?;
+      } else {
+        // TODO: undo delete
+      }
+    }
+
     let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
 
     let res = PostResponse { post: post_view };
index 9fa5731ba1cf16f9a1e54c329831c7e5d5b74122..4a5f18b7c4a6ef7a9f080defb7780f6a3296b9a4 100644 (file)
@@ -3,7 +3,7 @@ use super::*;
 impl ToApub for Comment {
   type Response = Note;
 
-  fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Note>, Error> {
+  fn to_apub(&self, conn: &PgConnection) -> Result<Note, Error> {
     let mut comment = Note::default();
     let oprops: &mut ObjectProperties = comment.as_mut();
     let creator = User_::read(&conn, self.creator_id)?;
@@ -33,7 +33,13 @@ impl ToApub for Comment {
       oprops.set_updated(convert_datetime(u))?;
     }
 
-    Ok(ResponseOrTombstone::Response(comment))
+    Ok(comment)
+  }
+}
+
+impl ToTombstone for Comment {
+  fn to_tombstone(&self) -> Result<Tombstone, Error> {
+    create_tombstone(self.deleted, &self.ap_id, self.published, self.updated)
   }
 }
 
@@ -102,7 +108,7 @@ impl ApubObjectType for Comment {
     create
       .create_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(note.as_response()?.to_owned())?;
+      .set_object_base_box(note)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -138,7 +144,7 @@ impl ApubObjectType for Comment {
     update
       .update_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(note.as_response()?.to_owned())?;
+      .set_object_base_box(note)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -157,6 +163,34 @@ impl ApubObjectType for Comment {
     )?;
     Ok(())
   }
+
+  // TODO: this code is literally copied from post.rs
+  fn send_delete(&self, actor: &User_, conn: &PgConnection) -> Result<(), Error> {
+    let mut delete = Delete::default();
+    delete
+      .delete_props
+      .set_actor_xsd_any_uri(actor.actor_id.to_owned())?
+      .set_object_base_box(BaseBox::from_concrete(self.to_tombstone()?)?)?;
+
+    // Insert the sent activity into the activity table
+    let activity_form = activity::ActivityForm {
+      user_id: self.creator_id,
+      data: serde_json::to_value(&delete)?,
+      local: true,
+      updated: None,
+    };
+    activity::Activity::create(&conn, &activity_form)?;
+
+    let post = Post::read(conn, self.post_id)?;
+    let community = Community::read(conn, post.community_id)?;
+    send_activity(
+      &delete,
+      &actor.private_key.to_owned().unwrap(),
+      &actor.actor_id,
+      community.get_follower_inboxes(&conn)?,
+    )?;
+    Ok(())
+  }
 }
 
 impl ApubLikeableType for Comment {
@@ -171,7 +205,7 @@ impl ApubLikeableType for Comment {
     like
       .like_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(note.as_response()?.to_owned())?;
+      .set_object_base_box(note)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -206,7 +240,7 @@ impl ApubLikeableType for Comment {
     dislike
       .dislike_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(note.as_response()?.to_owned())?;
+      .set_object_base_box(note)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
index ee3199954e2ae86850034b22e8e27fab011595d4..36e33c8951aefdb7012cf129bc1b0c8babdf056d 100644 (file)
@@ -9,17 +9,7 @@ impl ToApub for Community {
   type Response = GroupExt;
 
   // Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
-  fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<GroupExt>, Error> {
-    if self.deleted || self.removed {
-      let mut tombstone = Tombstone::default();
-      // TODO: might want to include updated/deleted times as well
-      tombstone
-        .object_props
-        .set_id(self.actor_id.to_owned())?
-        .set_published(convert_datetime(self.published))?;
-      return Ok(ResponseOrTombstone::Tombstone(Box::new(tombstone)));
-    }
-
+  fn to_apub(&self, conn: &PgConnection) -> Result<GroupExt, Error> {
     let mut group = Group::default();
     let oprops: &mut ObjectProperties = group.as_mut();
 
@@ -53,9 +43,13 @@ impl ToApub for Community {
       .set_endpoints(endpoint_props)?
       .set_followers(self.get_followers_url())?;
 
-    Ok(ResponseOrTombstone::Response(
-      group.extend(actor_props).extend(self.get_public_key_ext()),
-    ))
+    Ok(group.extend(actor_props).extend(self.get_public_key_ext()))
+  }
+}
+
+impl ToTombstone for Community {
+  fn to_tombstone(&self) -> Result<Tombstone, Error> {
+    create_tombstone(self.deleted, &self.actor_id, self.published, self.updated)
   }
 }
 
@@ -107,14 +101,11 @@ impl ActorType for Community {
   }
 
   fn send_delete(&self, conn: &PgConnection) -> Result<(), Error> {
-    let community = self.to_apub(conn)?;
     let mut delete = Delete::default();
     delete
       .delete_props
       .set_actor_xsd_any_uri(self.actor_id.to_owned())?
-      .set_object_base_box(BaseBox::from_concrete(
-        community.as_tombstone()?.to_owned(),
-      )?)?;
+      .set_object_base_box(BaseBox::from_concrete(self.to_tombstone()?)?)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -208,8 +199,13 @@ pub async fn get_apub_community_http(
   db: DbPoolParam,
 ) -> Result<HttpResponse<Body>, Error> {
   let community = Community::read_from_name(&&db.get()?, &info.community_name)?;
-  let c = community.to_apub(&db.get().unwrap())?;
-  Ok(create_apub_response(&c))
+  if !community.deleted {
+    Ok(create_apub_response(
+      &community.to_apub(&db.get().unwrap())?,
+    ))
+  } else {
+    Ok(create_apub_tombstone_response(&community.to_tombstone()?))
+  }
 }
 
 /// Returns an empty followers collection, only populating the siz (for privacy).
index 9232c2d7e3c4f3880012a8235abf8ab72b3e49e4..9d312cc3d2e8d9a6d231e7ecda0140790b75b000 100644 (file)
@@ -60,6 +60,7 @@ use crate::websocket::{
 use crate::{convert_datetime, naive_now, Settings};
 
 use activities::{populate_object_props, send_activity};
+use chrono::NaiveDateTime;
 use fetcher::{get_or_fetch_and_upsert_remote_community, get_or_fetch_and_upsert_remote_user};
 use signatures::verify;
 use signatures::{sign, PublicKey, PublicKeyExtension};
@@ -86,6 +87,14 @@ where
     .content_type(APUB_JSON_CONTENT_TYPE)
     .json(data)
 }
+fn create_apub_tombstone_response<T>(data: &T) -> HttpResponse<Body>
+where
+  T: Serialize,
+{
+  HttpResponse::Gone()
+    .content_type(APUB_JSON_CONTENT_TYPE)
+    .json(data)
+}
 
 /// Generates the ActivityPub ID for a given object type and name.
 ///
@@ -138,31 +147,40 @@ fn is_apub_id_valid(apub_id: &Url) -> bool {
   }
 }
 
-#[derive(Serialize)]
-pub enum ResponseOrTombstone<Response> {
-  Response(Response),
-  Tombstone(Box<Tombstone>),
+// TODO Not sure good names for these
+pub trait ToApub {
+  type Response;
+  fn to_apub(&self, conn: &PgConnection) -> Result<Self::Response, Error>;
 }
 
-impl<Response> ResponseOrTombstone<Response> {
-  fn as_response(&self) -> Result<&Response, Error> {
-    match self {
-      ResponseOrTombstone::Response(r) => Ok(r),
-      ResponseOrTombstone::Tombstone(_t) => Err(format_err!("Value is a tombstone")),
-    }
-  }
-  fn as_tombstone(&self) -> Result<&Tombstone, Error> {
-    match self {
-      ResponseOrTombstone::Tombstone(t) => Ok(t),
-      ResponseOrTombstone::Response(_r) => Err(format_err!("Value is a response")),
+fn create_tombstone(
+  deleted: bool,
+  object_id: &str,
+  published: NaiveDateTime,
+  updated: Option<NaiveDateTime>,
+) -> Result<Tombstone, Error> {
+  if deleted {
+    let mut tombstone = Tombstone::default();
+    // TODO: might want to include deleted time as well
+    tombstone
+      .object_props
+      .set_id(object_id)?
+      .set_published(convert_datetime(published))?;
+    if let Some(updated) = updated {
+      tombstone
+        .object_props
+        .set_updated(convert_datetime(updated))?;
     }
+    Ok(tombstone)
+  } else {
+    Err(format_err!(
+      "Cant convert object to tombstone if it wasnt deleted"
+    ))
   }
 }
 
-// TODO Not sure good names for these
-pub trait ToApub {
-  type Response;
-  fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Self::Response>, Error>;
+pub trait ToTombstone {
+  fn to_tombstone(&self) -> Result<Tombstone, Error>;
 }
 
 pub trait FromApub {
@@ -175,7 +193,7 @@ pub trait FromApub {
 pub trait ApubObjectType {
   fn send_create(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
   fn send_update(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
-  //fn send_delete(&self, creator: &User_, conn: &PgConnection) -> Result<(), Error>;
+  fn send_delete(&self, actor: &User_, conn: &PgConnection) -> Result<(), Error>;
 }
 
 pub trait ApubLikeableType {
index 381ba3c6cf939a2546d4f267363bd7ee657be942..77f8d9842815b57a78068baf6e2917cc7c38cca3 100644 (file)
@@ -12,14 +12,18 @@ pub async fn get_apub_post(
 ) -> Result<HttpResponse<Body>, Error> {
   let id = info.post_id.parse::<i32>()?;
   let post = Post::read(&&db.get()?, id)?;
-  Ok(create_apub_response(&post.to_apub(&db.get().unwrap())?))
+  if !post.deleted {
+    Ok(create_apub_response(&post.to_apub(&db.get().unwrap())?))
+  } else {
+    Ok(create_apub_tombstone_response(&post.to_tombstone()?))
+  }
 }
 
 impl ToApub for Post {
   type Response = Page;
 
   // Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
-  fn to_apub(&self, conn: &PgConnection) -> Result<ResponseOrTombstone<Page>, Error> {
+  fn to_apub(&self, conn: &PgConnection) -> Result<Page, Error> {
     let mut page = Page::default();
     let oprops: &mut ObjectProperties = page.as_mut();
     let creator = User_::read(conn, self.creator_id)?;
@@ -51,7 +55,13 @@ impl ToApub for Post {
       oprops.set_updated(convert_datetime(u))?;
     }
 
-    Ok(ResponseOrTombstone::Response(page))
+    Ok(page)
+  }
+}
+
+impl ToTombstone for Post {
+  fn to_tombstone(&self) -> Result<Tombstone, Error> {
+    create_tombstone(self.deleted, &self.ap_id, self.published, self.updated)
   }
 }
 
@@ -109,7 +119,7 @@ impl ApubObjectType for Post {
     create
       .create_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(page.as_response()?.to_owned())?;
+      .set_object_base_box(page)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -144,7 +154,7 @@ impl ApubObjectType for Post {
     update
       .update_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(page.as_response()?.to_owned())?;
+      .set_object_base_box(page)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -163,6 +173,32 @@ impl ApubObjectType for Post {
     )?;
     Ok(())
   }
+
+  fn send_delete(&self, actor: &User_, conn: &PgConnection) -> Result<(), Error> {
+    let mut delete = Delete::default();
+    delete
+      .delete_props
+      .set_actor_xsd_any_uri(actor.actor_id.to_owned())?
+      .set_object_base_box(BaseBox::from_concrete(self.to_tombstone()?)?)?;
+
+    // Insert the sent activity into the activity table
+    let activity_form = activity::ActivityForm {
+      user_id: self.creator_id,
+      data: serde_json::to_value(&delete)?,
+      local: true,
+      updated: None,
+    };
+    activity::Activity::create(&conn, &activity_form)?;
+
+    let community = Community::read(conn, self.community_id)?;
+    send_activity(
+      &delete,
+      &actor.private_key.to_owned().unwrap(),
+      &actor.actor_id,
+      community.get_follower_inboxes(&conn)?,
+    )?;
+    Ok(())
+  }
 }
 
 impl ApubLikeableType for Post {
@@ -176,7 +212,7 @@ impl ApubLikeableType for Post {
     like
       .like_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(page.as_response()?.to_owned())?;
+      .set_object_base_box(page)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
@@ -210,7 +246,7 @@ impl ApubLikeableType for Post {
     dislike
       .dislike_props
       .set_actor_xsd_any_uri(creator.actor_id.to_owned())?
-      .set_object_base_box(page.as_response()?.to_owned())?;
+      .set_object_base_box(page)?;
 
     // Insert the sent activity into the activity table
     let activity_form = activity::ActivityForm {
index 10ed1122dda6bff5cb0dab9af3c8087af11dff73..28cb71e2a6c2b1567eb84c6115209b1ab7f9aefc 100644 (file)
@@ -66,6 +66,7 @@ pub async fn shared_inbox(
       receive_dislike_comment(&d, &request, &conn, chat_server)
     }
     (SharedAcceptedObjects::Delete(d), Some("Tombstone")) => {
+      // TODO: is this deleting a community, post, comment or what?
       receive_delete_community(&d, &request, &conn, chat_server)
     }
     _ => Err(format_err!("Unknown incoming activity type.")),
index 36147f7a0d388d2ac8197186d045ced8faafc2ab..7426efd5e9dc525381caebd056a446b0adf6ebc8 100644 (file)
@@ -9,7 +9,7 @@ impl ToApub for User_ {
   type Response = PersonExt;
 
   // Turn a Lemmy Community into an ActivityPub group that can be sent out over the network.
-  fn to_apub(&self, _conn: &PgConnection) -> Result<ResponseOrTombstone<PersonExt>, Error> {
+  fn to_apub(&self, _conn: &PgConnection) -> Result<PersonExt, Error> {
     // TODO go through all these to_string and to_owned()
     let mut person = Person::default();
     let oprops: &mut ObjectProperties = person.as_mut();
@@ -41,9 +41,7 @@ impl ToApub for User_ {
       .set_following(self.get_following_url())?
       .set_liked(self.get_liked_url())?;
 
-    Ok(ResponseOrTombstone::Response(
-      person.extend(actor_props).extend(self.get_public_key_ext()),
-    ))
+    Ok(person.extend(actor_props).extend(self.get_public_key_ext()))
   }
 }