]> Untitled Git - lemmy.git/commitdiff
When announcing incoming activities, keep extra fields (#2550)
authorNutomic <me@nutomic.com>
Sat, 12 Nov 2022 13:52:57 +0000 (13:52 +0000)
committerGitHub <noreply@github.com>
Sat, 12 Nov 2022 13:52:57 +0000 (08:52 -0500)
41 files changed:
crates/apub/assets/lemmy/activities/block/block_user.json
crates/apub/assets/lemmy/activities/block/undo_block_user.json
crates/apub/assets/lemmy/collections/group_outbox.json
crates/apub/src/activities/block/block_user.rs
crates/apub/src/activities/block/undo_block_user.rs
crates/apub/src/activities/community/add_mod.rs
crates/apub/src/activities/community/announce.rs
crates/apub/src/activities/community/mod.rs
crates/apub/src/activities/community/remove_mod.rs
crates/apub/src/activities/community/report.rs
crates/apub/src/activities/community/update.rs
crates/apub/src/activities/create_or_update/comment.rs
crates/apub/src/activities/create_or_update/post.rs
crates/apub/src/activities/create_or_update/private_message.rs
crates/apub/src/activities/deletion/delete.rs
crates/apub/src/activities/deletion/undo_delete.rs
crates/apub/src/activities/following/accept.rs
crates/apub/src/activities/following/follow.rs
crates/apub/src/activities/following/undo_follow.rs
crates/apub/src/activities/voting/undo_vote.rs
crates/apub/src/activities/voting/vote.rs
crates/apub/src/activity_lists.rs
crates/apub/src/collections/community_outbox.rs
crates/apub/src/http/person.rs
crates/apub/src/protocol/activities/block/block_user.rs
crates/apub/src/protocol/activities/block/undo_block_user.rs
crates/apub/src/protocol/activities/community/add_mod.rs
crates/apub/src/protocol/activities/community/announce.rs
crates/apub/src/protocol/activities/community/remove_mod.rs
crates/apub/src/protocol/activities/community/report.rs
crates/apub/src/protocol/activities/community/update.rs
crates/apub/src/protocol/activities/create_or_update/comment.rs
crates/apub/src/protocol/activities/create_or_update/post.rs
crates/apub/src/protocol/activities/create_or_update/private_message.rs
crates/apub/src/protocol/activities/deletion/delete.rs
crates/apub/src/protocol/activities/deletion/undo_delete.rs
crates/apub/src/protocol/activities/following/accept.rs
crates/apub/src/protocol/activities/following/follow.rs
crates/apub/src/protocol/activities/following/undo_follow.rs
crates/apub/src/protocol/activities/voting/undo_vote.rs
crates/apub/src/protocol/activities/voting/vote.rs

index a12b68e7e54b00f0771bc07e4d035eb854ea6169..f400fa504828306005833d855560e4a389582c26 100644 (file)
@@ -9,7 +9,7 @@
   ],
   "target": "http://enterprise.lemmy.ml/c/main",
   "type": "Block",
-  "remove_data": "true",
+  "removeData": true,
   "summary": "spam post",
   "expires": "2021-11-01T12:23:50.151874+00:00",
   "id": "http://enterprise.lemmy.ml/activities/block/5d42fffb-0903-4625-86d4-0b39bb344fc2"
index 41c9aad7760818e9c9dc3b9621a4531686f4ce01..99f9077863303d8e4f1ae23bf7913ac4ed236a20 100644 (file)
@@ -14,7 +14,7 @@
     ],
     "target": "http://enterprise.lemmy.ml/c/main",
     "type": "Block",
-    "remove_data": "true",
+    "removeData": true,
     "summary": "spam post",
     "expires": "2021-11-01T12:23:50.151874+00:00",
     "id": "http://enterprise.lemmy.ml/activities/block/726f43ab-bd0e-4ab3-89c8-627e976f553c"
index 147891771fa4b516eabc986955082fa34e7747e8..d39c12d9eb4e029f39827d51dffd21fe3b8c49cc 100644 (file)
@@ -1,61 +1,81 @@
 {
-  "type": "OrderedCollection",
-  "id": "https://ds9.lemmy.ml/c/testcom/outbox",
-  "totalItems": 2,
-  "orderedItems": [
+  "type":"OrderedCollection",
+  "id":"https://ds9.lemmy.ml/c/testcom/outbox",
+  "totalItems":2,
+  "orderedItems":[
     {
-      "actor": "https://ds9.lemmy.ml/c/testcom",
-      "to": [
+      "actor":"https://ds9.lemmy.ml/c/testcom",
+      "to":[
         "https://www.w3.org/ns/activitystreams#Public"
       ],
-      "object": {
-        "type": "Page",
-        "id": "https://ds9.lemmy.ml/post/2328",
-        "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
-        "to": [
-          "https://ds9.lemmy.ml/c/testcom",
+      "object":{
+        "actor":"https://ds9.lemmy.ml/u/nutomic",
+        "to":[
           "https://www.w3.org/ns/activitystreams#Public"
         ],
-        "cc": [],
-        "name": "another outbox test",
-        "mediaType": "text/html",
-        "commentsEnabled": true,
-        "sensitive": false,
-        "stickied": false,
-        "published": "2021-11-18T17:19:45.895163+00:00"
+        "cc":[
+          "https://ds9.lemmy.ml/c/testcom"
+        ],
+        "type":"Create",
+        "id":"http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf",
+        "object":{
+          "type":"Page",
+          "id":"https://ds9.lemmy.ml/post/2328",
+          "attributedTo":"https://ds9.lemmy.ml/u/nutomic",
+          "to":[
+            "https://ds9.lemmy.ml/c/testcom",
+            "https://www.w3.org/ns/activitystreams#Public"
+          ],
+          "name":"another outbox test",
+          "mediaType":"text/html",
+          "commentsEnabled":true,
+          "sensitive":false,
+          "stickied":false,
+          "published":"2021-11-18T17:19:45.895163+00:00"
+        }
       },
-      "cc": [
+      "cc":[
         "https://ds9.lemmy.ml/c/testcom/followers"
       ],
-      "type": "Announce",
-      "id": "https://ds9.lemmy.ml/activities/announce/b204fe9f-b13d-4af2-9d22-239ac2d892e6"
+      "type":"Announce",
+      "id":"https://ds9.lemmy.ml/activities/announce/b204fe9f-b13d-4af2-9d22-239ac2d892e6"
     },
     {
-      "actor": "https://ds9.lemmy.ml/c/testcom",
-      "to": [
+      "actor":"https://ds9.lemmy.ml/c/testcom",
+      "to":[
         "https://www.w3.org/ns/activitystreams#Public"
       ],
-      "object": {
-        "type": "Page",
-        "id": "https://ds9.lemmy.ml/post/2327",
-        "attributedTo": "https://ds9.lemmy.ml/u/nutomic",
-        "to": [
-          "https://ds9.lemmy.ml/c/testcom",
+      "object":{
+        "actor":"https://ds9.lemmy.ml/u/nutomic",
+        "to":[
           "https://www.w3.org/ns/activitystreams#Public"
         ],
-        "cc": [],
-        "name": "outbox test",
-        "mediaType": "text/html",
-        "commentsEnabled": true,
-        "sensitive": false,
-        "stickied": false,
-        "published": "2021-11-18T17:19:05.763109+00:00"
+        "cc":[
+          "https://ds9.lemmy.ml/c/testcom"
+        ],
+        "type":"Create",
+        "id":"http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf",
+        "object":{
+          "type":"Page",
+          "id":"https://ds9.lemmy.ml/post/2327",
+          "attributedTo":"https://ds9.lemmy.ml/u/nutomic",
+          "to":[
+            "https://ds9.lemmy.ml/c/testcom",
+            "https://www.w3.org/ns/activitystreams#Public"
+          ],
+          "name":"outbox test",
+          "mediaType":"text/html",
+          "commentsEnabled":true,
+          "sensitive":false,
+          "stickied":false,
+          "published":"2021-11-18T17:19:05.763109+00:00"
+        }
       },
-      "cc": [
+      "cc":[
         "https://ds9.lemmy.ml/c/testcom/followers"
       ],
-      "type": "Announce",
-      "id": "https://ds9.lemmy.ml/activities/announce/c6c960ce-c8d8-4231-925e-3ba367468f18"
+      "type":"Announce",
+      "id":"https://ds9.lemmy.ml/activities/announce/c6c960ce-c8d8-4231-925e-3ba367468f18"
     }
   ]
 }
\ No newline at end of file
index 540847072fcf942b1e65e5d587a009b018d4d088..f27ec27da70bf7dedd99dd976d77ff6a69d1ca27 100644 (file)
@@ -65,7 +65,6 @@ impl BlockUser {
         &context.settings().get_protocol_and_hostname(),
       )?,
       expires: expires.map(convert_datetime),
-      unparsed: Default::default(),
     })
   }
 
index f18516f90b0b780efaba5d08f7b8712187051d1e..bf177ae8f8c82f1e9aacf6e894eb8e932a221b3a 100644 (file)
@@ -53,7 +53,6 @@ impl UndoBlockUser {
       cc: generate_cc(target, context.pool()).await?,
       kind: UndoType::Undo,
       id: id.clone(),
-      unparsed: Default::default(),
     };
 
     let mut inboxes = vec![user.shared_inbox_or_inbox()];
index ba78ec3b92fdf3e8949e7883d055ea0bde518657..6d7f96334c0e83299604f7207511c91fed6d9d50 100644 (file)
@@ -55,7 +55,6 @@ impl AddMod {
       cc: vec![community.actor_id()],
       kind: AddType::Add,
       id: id.clone(),
-      unparsed: Default::default(),
     };
 
     let activity = AnnouncableActivities::AddMod(add);
index e5419680ef9fda18266e121d34b4cc5a90c008a9..f99a650fba592c4b5532ae232d7ec0b2c77cca0f 100644 (file)
@@ -1,10 +1,16 @@
 use crate::{
-  activities::{generate_activity_id, send_lemmy_activity, verify_is_public},
+  activities::{
+    generate_activity_id,
+    send_lemmy_activity,
+    verify_is_public,
+    verify_person_in_community,
+  },
   activity_lists::AnnouncableActivities,
   insert_activity,
   objects::community::ApubCommunity,
   protocol::{
-    activities::{community::announce::AnnounceActivity, CreateOrUpdateType},
+    activities::community::announce::{AnnounceActivity, RawAnnouncableActivities},
+    Id,
     IdOrNestedObject,
   },
   ActorType,
@@ -13,9 +19,59 @@ use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::Acti
 use activitystreams_kinds::{activity::AnnounceType, public};
 use lemmy_utils::error::LemmyError;
 use lemmy_websocket::LemmyContext;
+use serde_json::Value;
 use tracing::debug;
 use url::Url;
 
+#[async_trait::async_trait(?Send)]
+impl ActivityHandler for RawAnnouncableActivities {
+  type DataType = LemmyContext;
+  type Error = LemmyError;
+
+  fn id(&self) -> &Url {
+    &self.id
+  }
+
+  fn actor(&self) -> &Url {
+    &self.actor
+  }
+
+  #[tracing::instrument(skip_all)]
+  async fn verify(
+    &self,
+    _data: &Data<Self::DataType>,
+    _request_counter: &mut i32,
+  ) -> Result<(), Self::Error> {
+    Ok(())
+  }
+
+  #[tracing::instrument(skip_all)]
+  async fn receive(
+    self,
+    data: &Data<Self::DataType>,
+    request_counter: &mut i32,
+  ) -> Result<(), Self::Error> {
+    let activity: AnnouncableActivities = self.clone().try_into()?;
+    // This is only for sending, not receiving so we reject it.
+    if let AnnouncableActivities::Page(_) = activity {
+      return Err(LemmyError::from_message("Cant receive page"));
+    }
+    let community = activity.get_community(data, &mut 0).await?;
+    let actor_id = ObjectId::new(activity.actor().clone());
+
+    // verify and receive activity
+    activity.verify(data, request_counter).await?;
+    activity.receive(data, request_counter).await?;
+
+    // send to community followers
+    if community.local {
+      verify_person_in_community(&actor_id, &community, data, &mut 0).await?;
+      AnnounceActivity::send(self, &community, data).await?;
+    }
+    Ok(())
+  }
+}
+
 #[async_trait::async_trait(?Send)]
 pub(crate) trait GetCommunity {
   async fn get_community(
@@ -27,7 +83,7 @@ pub(crate) trait GetCommunity {
 
 impl AnnounceActivity {
   pub(crate) fn new(
-    object: AnnouncableActivities,
+    object: RawAnnouncableActivities,
     community: &ApubCommunity,
     context: &LemmyContext,
   ) -> Result<AnnounceActivity, LemmyError> {
@@ -41,13 +97,12 @@ impl AnnounceActivity {
         &AnnounceType::Announce,
         &context.settings().get_protocol_and_hostname(),
       )?,
-      unparsed: Default::default(),
     })
   }
 
   #[tracing::instrument(skip_all)]
   pub async fn send(
-    object: AnnouncableActivities,
+    object: RawAnnouncableActivities,
     community: &ApubCommunity,
     context: &LemmyContext,
   ) -> Result<(), LemmyError> {
@@ -57,13 +112,18 @@ impl AnnounceActivity {
 
     // Pleroma and Mastodon can't handle activities like Announce/Create/Page. So for
     // compatibility, we also send Announce/Page so that they can follow Lemmy communities.
-    use AnnouncableActivities::*;
-    let object = match object {
-      CreateOrUpdatePost(c) if c.kind == CreateOrUpdateType::Create => Page(c.object),
-      _ => return Ok(()),
-    };
-    let announce_compat = AnnounceActivity::new(object, community, context)?;
-    send_lemmy_activity(context, announce_compat, community, inboxes, false).await?;
+    let object_parsed = object.try_into()?;
+    if let AnnouncableActivities::CreateOrUpdatePost(c) = object_parsed {
+      // Hack: need to convert Page into a format which can be sent as activity, which requires
+      //       adding actor field.
+      let announcable_page = RawAnnouncableActivities {
+        id: c.object.id.clone().into_inner(),
+        actor: c.actor.clone().into_inner(),
+        other: serde_json::to_value(c.object)?.as_object().unwrap().clone(),
+      };
+      let announce_compat = AnnounceActivity::new(announcable_page, community, context)?;
+      send_lemmy_activity(context, announce_compat, community, inboxes, false).await?;
+    }
     Ok(())
   }
 }
@@ -97,27 +157,53 @@ impl ActivityHandler for AnnounceActivity {
     context: &Data<LemmyContext>,
     request_counter: &mut i32,
   ) -> Result<(), LemmyError> {
-    let object = self.object.object(context, request_counter).await?;
+    let object: AnnouncableActivities = self
+      .object
+      .object(context, request_counter)
+      .await?
+      .try_into()?;
+    // This is only for sending, not receiving so we reject it.
+    if let AnnouncableActivities::Page(_) = object {
+      return Err(LemmyError::from_message("Cant receive page"));
+    }
+
     // we have to verify this here in order to avoid fetching the object twice over http
     object.verify(context, request_counter).await?;
 
-    // TODO: this can probably be implemented in a cleaner way
-    match object {
-      // Dont insert these into activities table, as they are not activities.
-      AnnouncableActivities::Page(_) => {}
-      _ => {
-        let object_value = serde_json::to_value(&object)?;
-        let insert =
-          insert_activity(object.id(), object_value, false, true, context.pool()).await?;
-        if !insert {
-          debug!(
-            "Received duplicate activity in announce {}",
-            object.id().to_string()
-          );
-          return Ok(());
-        }
-      }
+    let object_value = serde_json::to_value(&object)?;
+    let insert = insert_activity(object.id(), object_value, false, true, context.pool()).await?;
+    if !insert {
+      debug!(
+        "Received duplicate activity in announce {}",
+        object.id().to_string()
+      );
+      return Ok(());
     }
     object.receive(context, request_counter).await
   }
 }
+
+impl Id for RawAnnouncableActivities {
+  fn object_id(&self) -> &Url {
+    ActivityHandler::id(self)
+  }
+}
+
+impl TryFrom<RawAnnouncableActivities> for AnnouncableActivities {
+  type Error = serde_json::error::Error;
+
+  fn try_from(value: RawAnnouncableActivities) -> Result<Self, Self::Error> {
+    let mut map = value.other.clone();
+    map.insert("id".to_string(), Value::String(value.id.to_string()));
+    map.insert("actor".to_string(), Value::String(value.actor.to_string()));
+    serde_json::from_value(Value::Object(map))
+  }
+}
+
+impl TryFrom<AnnouncableActivities> for RawAnnouncableActivities {
+  type Error = serde_json::error::Error;
+
+  fn try_from(value: AnnouncableActivities) -> Result<Self, Self::Error> {
+    serde_json::from_value(serde_json::to_value(value)?)
+  }
+}
index 4d96ca4c7dde0831e060c7644e8aa09dacabdf6f..aed7ddb902714b6e8a7f8c82bec054eb9b6f5527 100644 (file)
@@ -32,7 +32,7 @@ where
   send_lemmy_activity(context, activity.clone(), actor, inboxes, false).await?;
 
   if community.local {
-    AnnounceActivity::send(activity, community, context).await?;
+    AnnounceActivity::send(activity.try_into()?, community, context).await?;
   }
 
   Ok(())
index 82c499e430befe2998debe1dd1ed9461991bd23a..2f2419f5a9a06f5f59382f57c3ebe94186f565af 100644 (file)
@@ -55,7 +55,6 @@ impl RemoveMod {
       id: id.clone(),
       cc: vec![community.actor_id()],
       kind: RemoveType::Remove,
-      unparsed: Default::default(),
     };
 
     let activity = AnnouncableActivities::RemoveMod(remove);
index 33322bf380843e87e2a341262bbc40e62b0189ec..867307f58d9871fbaa8dab98f0e7c31b78cc9352 100644 (file)
@@ -47,7 +47,6 @@ impl Report {
       summary: reason,
       kind,
       id: id.clone(),
-      unparsed: Default::default(),
     };
 
     let inbox = vec![community.shared_inbox_or_inbox()];
index f19aafeca9db735e4069b63a99180f6a4fbfb0f1..a9134d47350be8c2322b79077c68184ee63e6a2f 100644 (file)
@@ -41,7 +41,6 @@ impl UpdateCommunity {
       cc: vec![community.actor_id()],
       kind: UpdateType::Update,
       id: id.clone(),
-      unparsed: Default::default(),
     };
 
     let activity = AnnouncableActivities::UpdateCommunity(update);
index 1c6ce5111db6e8fb489612a163af219eed973faa..e367bec9a4720aeaea2c7c4817af113d9a3daba7 100644 (file)
@@ -63,7 +63,6 @@ impl CreateOrUpdateComment {
       object: note,
       kind,
       id: id.clone(),
-      unparsed: Default::default(),
     };
 
     let tagged_users: Vec<ObjectId<ApubPerson>> = create_or_update
index 09e9ae0d32af4a7e3b0992c021d7efff15a13045..4470f3b3ae2b315bcfe16ea9961843e8c48a4d5c 100644 (file)
@@ -49,7 +49,6 @@ impl CreateOrUpdatePost {
       cc: vec![community.actor_id()],
       kind,
       id: id.clone(),
-      unparsed: Default::default(),
     })
   }
 
@@ -65,7 +64,8 @@ impl CreateOrUpdatePost {
 
     let create_or_update = CreateOrUpdatePost::new(post, actor, &community, kind, context).await?;
     let activity = AnnouncableActivities::CreateOrUpdatePost(Box::new(create_or_update));
-    send_activity_in_community(activity, actor, &community, vec![], context).await
+    send_activity_in_community(activity, actor, &community, vec![], context).await?;
+    Ok(())
   }
 }
 
index 523135db770b95887e5885e32496caaf3850cca1..e07661961805af4995884589919e953557dc9f9f 100644 (file)
@@ -39,7 +39,6 @@ impl CreateOrUpdatePrivateMessage {
       to: [ObjectId::new(recipient.actor_id())],
       object: private_message.into_apub(context).await?,
       kind,
-      unparsed: Default::default(),
     };
     let inbox = vec![recipient.shared_inbox_or_inbox()];
     send_lemmy_activity(context, create_or_update, actor, inbox, true).await
index 0124f23313dec0a755e58933a7306695aeeaebdc..8d296332e01a083151f74f8498a3b04a80b41efa 100644 (file)
@@ -117,7 +117,6 @@ impl Delete {
       kind: DeleteType::Delete,
       summary,
       id,
-      unparsed: Default::default(),
     })
   }
 }
index 29f75e6d6d6d6c51cc0eac9a5adc3ddfcfb80ae6..c3533ad5e5c2964e0d39c3ab9259f4b057d1a2ce 100644 (file)
@@ -117,7 +117,6 @@ impl UndoDelete {
       cc: cc.into_iter().collect(),
       kind: UndoType::Undo,
       id,
-      unparsed: Default::default(),
     })
   }
 
index 55a37449504c467427b4fcfe9494f9a40dce7111..bda5a0acdcad3bf0444d3f2c2bc759e5be5fc388 100644 (file)
@@ -40,7 +40,6 @@ impl AcceptFollowCommunity {
         AcceptType::Accept,
         &context.settings().get_protocol_and_hostname(),
       )?,
-      unparsed: Default::default(),
     };
     let inbox = vec![person.shared_inbox_or_inbox()];
     send_lemmy_activity(context, accept, &community, inbox, true).await
index 57390b7fbae95b9457628c5c5fdac5154c980ee8..ad441091e7a4043bea3187d67821f0764fd06c66 100644 (file)
@@ -38,7 +38,6 @@ impl FollowCommunity {
         FollowType::Follow,
         &context.settings().get_protocol_and_hostname(),
       )?,
-      unparsed: Default::default(),
     })
   }
 
index 221d8184f8c865853f206c0b4635d68e6af91718..b90039cd044757e7186c443719278720746c6c43 100644 (file)
@@ -36,7 +36,6 @@ impl UndoFollowCommunity {
         UndoType::Undo,
         &context.settings().get_protocol_and_hostname(),
       )?,
-      unparsed: Default::default(),
     };
     let inbox = vec![community.shared_inbox_or_inbox()];
     send_lemmy_activity(context, undo, actor, inbox, true).await
index 9415e5477947d211ac4afb2e4f6a0bd1139faf84..8980e71ff41ff80da05a79acd8ba3a346256b571 100644 (file)
@@ -51,7 +51,6 @@ impl UndoVote {
       object,
       kind: UndoType::Undo,
       id: id.clone(),
-      unparsed: Default::default(),
     };
     let activity = AnnouncableActivities::UndoVote(undo_vote);
     send_activity_in_community(activity, actor, &community, vec![], context).await
index 8a022f7d249f88c430f024a39f991f3344f19d21..6608ad9c8d11e6b5babadfbb0c607aae325101b4 100644 (file)
@@ -37,7 +37,6 @@ impl Vote {
       object: ObjectId::new(object.ap_id()),
       kind: kind.clone(),
       id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
-      unparsed: Default::default(),
     })
   }
 
index dbd185bddebf2bdc3cb913a8aac0aa0ad7d06c60..86e87a2a3cc047f16a08b947a29398f2e5077a21 100644 (file)
@@ -1,12 +1,12 @@
 use crate::{
-  activities::{community::announce::GetCommunity, verify_person_in_community},
+  activities::community::announce::GetCommunity,
   objects::community::ApubCommunity,
   protocol::{
     activities::{
       block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
       community::{
         add_mod::AddMod,
-        announce::AnnounceActivity,
+        announce::{AnnounceActivity, RawAnnouncableActivities},
         remove_mod::RemoveMod,
         report::Report,
         update::UpdateCommunity,
@@ -25,15 +25,9 @@ use crate::{
       voting::{undo_vote::UndoVote, vote::Vote},
     },
     objects::page::Page,
-    Id,
   },
 };
-use activitypub_federation::{
-  core::object_id::ObjectId,
-  data::Data,
-  deser::context::WithContext,
-  traits::{activity_handler, ActivityHandler},
-};
+use activitypub_federation::{deser::context::WithContext, traits::activity_handler};
 use lemmy_utils::error::LemmyError;
 use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
@@ -43,19 +37,19 @@ use url::Url;
 #[serde(untagged)]
 #[activity_handler(LemmyContext, LemmyError)]
 pub enum SharedInboxActivities {
-  GroupInboxActivities(Box<WithContext<GroupInboxActivities>>),
-  // Note, pm activities need to be at the end, otherwise comments will end up here. We can probably
-  // avoid this problem by replacing createpm.object with our own struct, instead of NoteExt.
   PersonInboxActivities(Box<WithContext<PersonInboxActivities>>),
+  GroupInboxActivities(Box<WithContext<GroupInboxActivities>>),
 }
 
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(untagged)]
+#[activity_handler(LemmyContext, LemmyError)]
 pub enum GroupInboxActivities {
   FollowCommunity(FollowCommunity),
   UndoFollowCommunity(UndoFollowCommunity),
-  AnnouncableActivities(Box<AnnouncableActivities>),
   Report(Report),
+  // This is a catch-all and needs to be last
+  AnnouncableActivities(RawAnnouncableActivities),
 }
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
@@ -63,14 +57,23 @@ pub enum GroupInboxActivities {
 #[activity_handler(LemmyContext, LemmyError)]
 pub enum PersonInboxActivities {
   AcceptFollowCommunity(AcceptFollowCommunity),
-  /// Some activities can also be sent from user to user, eg a comment with mentions
-  AnnouncableActivities(AnnouncableActivities),
   CreateOrUpdatePrivateMessage(CreateOrUpdatePrivateMessage),
   Delete(Delete),
   UndoDelete(UndoDelete),
   AnnounceActivity(AnnounceActivity),
 }
 
+/// This is necessary for user inbox, which can also receive some "announcable" activities,
+/// eg a comment mention. This needs to be a separate enum so that announcables received in shared
+/// inbox can fall through to be parsed as GroupInboxActivities::AnnouncableActivities.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(untagged)]
+#[activity_handler(LemmyContext, LemmyError)]
+pub enum PersonInboxActivitiesWithAnnouncable {
+  PersonInboxActivities(PersonInboxActivities),
+  AnnouncableActivities(AnnouncableActivities),
+}
+
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[serde(untagged)]
 #[activity_handler(LemmyContext, LemmyError)]
@@ -127,77 +130,6 @@ impl GetCommunity for AnnouncableActivities {
   }
 }
 
-impl Id for AnnouncableActivities {
-  fn object_id(&self) -> &Url {
-    ActivityHandler::id(self)
-  }
-}
-
-// Need to implement this manually to announce matching activities
-#[async_trait::async_trait(?Send)]
-impl ActivityHandler for GroupInboxActivities {
-  type DataType = LemmyContext;
-  type Error = LemmyError;
-
-  fn id(&self) -> &Url {
-    match self {
-      GroupInboxActivities::FollowCommunity(a) => a.id(),
-      GroupInboxActivities::UndoFollowCommunity(a) => a.id(),
-      GroupInboxActivities::AnnouncableActivities(a) => a.object_id(),
-      GroupInboxActivities::Report(a) => a.id(),
-    }
-  }
-
-  fn actor(&self) -> &Url {
-    match self {
-      GroupInboxActivities::FollowCommunity(a) => a.actor(),
-      GroupInboxActivities::UndoFollowCommunity(a) => a.actor(),
-      GroupInboxActivities::AnnouncableActivities(a) => a.actor(),
-      GroupInboxActivities::Report(a) => a.actor(),
-    }
-  }
-
-  async fn verify(
-    &self,
-    data: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    match self {
-      GroupInboxActivities::FollowCommunity(a) => a.verify(data, request_counter).await,
-      GroupInboxActivities::UndoFollowCommunity(a) => a.verify(data, request_counter).await,
-      GroupInboxActivities::AnnouncableActivities(a) => a.verify(data, request_counter).await,
-      GroupInboxActivities::Report(a) => a.verify(data, request_counter).await,
-    }
-  }
-
-  async fn receive(
-    self,
-    data: &Data<Self::DataType>,
-    request_counter: &mut i32,
-  ) -> Result<(), LemmyError> {
-    match self {
-      GroupInboxActivities::FollowCommunity(a) => a.receive(data, request_counter).await,
-      GroupInboxActivities::UndoFollowCommunity(a) => a.receive(data, request_counter).await,
-      GroupInboxActivities::AnnouncableActivities(activity) => {
-        activity.clone().receive(data, request_counter).await?;
-
-        // Ignore failures in get_community(). those happen because Delete/PrivateMessage is not in a
-        // community, but looks identical to Delete/Post or Delete/Comment which are in a community.
-        let community = activity.get_community(data, &mut 0).await;
-        if let Ok(community) = community {
-          if community.local {
-            let actor_id = ObjectId::new(activity.actor().clone());
-            verify_person_in_community(&actor_id, &community, data, &mut 0).await?;
-            AnnounceActivity::send(*activity, &community, data).await?;
-          }
-        }
-        Ok(())
-      }
-      GroupInboxActivities::Report(a) => a.receive(data, request_counter).await,
-    }
-  }
-}
-
 #[cfg(test)]
 mod tests {
   use crate::{
index d9fbf4f23982e2547bf59c6e5dc10220fd45b144..57fc48be6ae729d7b098a754ae9bd4038f33fee8 100644 (file)
@@ -4,7 +4,11 @@ use crate::{
   generate_outbox_url,
   objects::post::ApubPost,
   protocol::{
-    activities::community::announce::AnnounceActivity,
+    activities::{
+      community::announce::AnnounceActivity,
+      create_or_update::post::CreateOrUpdatePost,
+      CreateOrUpdateType,
+    },
     collections::group_outbox::GroupOutbox,
   },
 };
@@ -16,7 +20,10 @@ use activitypub_federation::{
 use activitystreams_kinds::collection::OrderedCollectionType;
 use chrono::NaiveDateTime;
 use futures::future::join_all;
-use lemmy_db_schema::source::post::Post;
+use lemmy_db_schema::{
+  source::{person::Person, post::Post},
+  traits::Crud,
+};
 use lemmy_utils::error::LemmyError;
 use url::Url;
 
@@ -61,9 +68,12 @@ impl ApubObject for ApubCommunityOutbox {
   async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
     let mut ordered_items = vec![];
     for post in self.0 {
-      let page = post.into_apub(&data.1).await?;
-      let announcable = AnnouncableActivities::Page(page);
-      let announce = AnnounceActivity::new(announcable, &data.0, &data.1)?;
+      let person = Person::read(data.1.pool(), post.creator_id).await?.into();
+      let create =
+        CreateOrUpdatePost::new(post, &person, &data.0, CreateOrUpdateType::Create, &data.1)
+          .await?;
+      let announcable = AnnouncableActivities::CreateOrUpdatePost(Box::new(create));
+      let announce = AnnounceActivity::new(announcable.try_into()?, &data.0, &data.1)?;
       ordered_items.push(announce);
     }
 
index bf82a47c9305c0fc1ee447b7a2c312b98bc0c512..1653697bec1b3390d5abc1b264684fdf224af6e7 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{
-  activity_lists::PersonInboxActivities,
+  activity_lists::PersonInboxActivitiesWithAnnouncable,
   fetcher::user_or_community::UserOrCommunity,
   generate_outbox_url,
   http::{create_apub_response, create_apub_tombstone_response, receive_lemmy_activity},
@@ -45,7 +45,7 @@ pub async fn person_inbox(
   payload: String,
   context: web::Data<LemmyContext>,
 ) -> Result<HttpResponse, LemmyError> {
-  receive_lemmy_activity::<WithContext<PersonInboxActivities>, UserOrCommunity>(
+  receive_lemmy_activity::<WithContext<PersonInboxActivitiesWithAnnouncable>, UserOrCommunity>(
     request, payload, context,
   )
   .await
index 1929a6a53483278fb13104fdc0429e2fb66e6322..3925c55c790def35d7ab7da3b623ddccf58176b6 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{activities::block::SiteOrCommunity, objects::person::ApubPerson, protocol::Unparsed};
+use crate::{activities::block::SiteOrCommunity, objects::person::ApubPerson};
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::BlockType;
 use chrono::{DateTime, FixedOffset};
@@ -25,6 +25,4 @@ pub struct BlockUser {
   /// block reason, written to mod log
   pub(crate) summary: Option<String>,
   pub(crate) expires: Option<DateTime<FixedOffset>>,
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index b2dcfaffa5efdf06102f2ff022e39b2f9548ebf9..df1611437caed80be51af88869c903cecfeccb67 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-  objects::person::ApubPerson,
-  protocol::{activities::block::block_user::BlockUser, Unparsed},
-};
+use crate::{objects::person::ApubPerson, protocol::activities::block::block_user::BlockUser};
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::UndoType;
 use serde::{Deserialize, Serialize};
@@ -19,7 +16,4 @@ pub struct UndoBlockUser {
   #[serde(rename = "type")]
   pub(crate) kind: UndoType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index e720b8e6de48f00ec0a4b48306baabea6f768a98..b9ce2420ae495a2619a2cc032a8c420b9609cde2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{objects::person::ApubPerson, protocol::Unparsed};
+use crate::objects::person::ApubPerson;
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::AddType;
 use serde::{Deserialize, Serialize};
@@ -17,7 +17,4 @@ pub struct AddMod {
   #[serde(rename = "type")]
   pub(crate) kind: AddType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 9db17a0fef48cfc2f5085740da87c160c338733b..7c2e16ec6b648775c56e2d639a2b9c00cb0fa676 100644 (file)
@@ -1,11 +1,8 @@
-use crate::{
-  activity_lists::AnnouncableActivities,
-  objects::community::ApubCommunity,
-  protocol::{IdOrNestedObject, Unparsed},
-};
+use crate::{objects::community::ApubCommunity, protocol::IdOrNestedObject};
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::AnnounceType;
 use serde::{Deserialize, Serialize};
+use serde_json::{Map, Value};
 use url::Url;
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
@@ -14,13 +11,20 @@ pub struct AnnounceActivity {
   pub(crate) actor: ObjectId<ApubCommunity>,
   #[serde(deserialize_with = "deserialize_one_or_many")]
   pub(crate) to: Vec<Url>,
-  pub(crate) object: IdOrNestedObject<AnnouncableActivities>,
+  pub(crate) object: IdOrNestedObject<RawAnnouncableActivities>,
   #[serde(deserialize_with = "deserialize_one_or_many")]
   pub(crate) cc: Vec<Url>,
   #[serde(rename = "type")]
   pub(crate) kind: AnnounceType,
   pub(crate) id: Url,
+}
 
+/// Use this to receive community inbox activities, and then announce them if valid. This
+/// ensures that all json fields are kept, even if Lemmy doesnt understand them.
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct RawAnnouncableActivities {
+  pub(crate) id: Url,
+  pub(crate) actor: Url,
   #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
+  pub(crate) other: Map<String, Value>,
 }
index bd972202f7f7e068a4718e7666b5a246a007b64c..6fd20af4b22e5be596e135c2daa21457d4c79be5 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{objects::person::ApubPerson, protocol::Unparsed};
+use crate::objects::person::ApubPerson;
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::RemoveType;
 use serde::{Deserialize, Serialize};
@@ -17,7 +17,4 @@ pub struct RemoveMod {
   pub(crate) kind: RemoveType,
   pub(crate) target: Url,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 4c2649eeffff8e519713df87d3a197d2388fd9c7..f9830c85dbec047a2c15a8e734528af3d201e0e3 100644 (file)
@@ -1,7 +1,6 @@
 use crate::{
   fetcher::post_or_comment::PostOrComment,
   objects::{community::ApubCommunity, person::ApubPerson},
-  protocol::Unparsed,
 };
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one};
 use activitystreams_kinds::activity::FlagType;
@@ -19,7 +18,4 @@ pub struct Report {
   #[serde(rename = "type")]
   pub(crate) kind: FlagType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index d0b27a5512e1785e5446d0551b9e04a85168f335..f6ef99c0938e23b23ac3b2bf242823f137b79c4d 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-  objects::person::ApubPerson,
-  protocol::{objects::group::Group, Unparsed},
-};
+use crate::{objects::person::ApubPerson, protocol::objects::group::Group};
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::UpdateType;
 use serde::{Deserialize, Serialize};
@@ -22,7 +19,4 @@ pub struct UpdateCommunity {
   #[serde(rename = "type")]
   pub(crate) kind: UpdateType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 5ebc0f5548eec4b515122662521e0eb8207bce63..3049b79c09e72d3e361d940e52c25a619f7e5c89 100644 (file)
@@ -1,7 +1,7 @@
 use crate::{
   mentions::MentionOrValue,
   objects::person::ApubPerson,
-  protocol::{activities::CreateOrUpdateType, objects::note::Note, Unparsed},
+  protocol::{activities::CreateOrUpdateType, objects::note::Note},
 };
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use serde::{Deserialize, Serialize};
@@ -21,7 +21,4 @@ pub struct CreateOrUpdateComment {
   #[serde(rename = "type")]
   pub(crate) kind: CreateOrUpdateType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index d40073cf336baa4b8897542232c72de9c5b499e8..70b15677020cd0a31f736bbac4e27666c35dcf4c 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::person::ApubPerson,
-  protocol::{activities::CreateOrUpdateType, objects::page::Page, Unparsed},
+  protocol::{activities::CreateOrUpdateType, objects::page::Page},
 };
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use serde::{Deserialize, Serialize};
@@ -18,7 +18,4 @@ pub struct CreateOrUpdatePost {
   #[serde(rename = "type")]
   pub(crate) kind: CreateOrUpdateType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 9cee8ddf3840babc08ae442abdb06134a1ea602f..6a9b585bfd33a0ba8da2ee1041e7f8df2a22b18f 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::person::ApubPerson,
-  protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage, Unparsed},
+  protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage},
 };
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one};
 use serde::{Deserialize, Serialize};
@@ -16,7 +16,4 @@ pub struct CreateOrUpdatePrivateMessage {
   pub(crate) object: ChatMessage,
   #[serde(rename = "type")]
   pub(crate) kind: CreateOrUpdateType,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 76256cacbba29cce9d275d38b5c9076519ef8866..d3dcaf57995eb93bf015d6f0f93e42a89115cc72 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::person::ApubPerson,
-  protocol::{objects::tombstone::Tombstone, IdOrNestedObject, Unparsed},
+  protocol::{objects::tombstone::Tombstone, IdOrNestedObject},
 };
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::DeleteType;
@@ -27,6 +27,4 @@ pub struct Delete {
   /// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
   /// deleting their own content.
   pub(crate) summary: Option<String>,
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 1ae6aa84b80434dc388024907af02244336ddfde..02cbf1785f44f40a821beb8e4714d1dd37115b6e 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-  objects::person::ApubPerson,
-  protocol::{activities::deletion::delete::Delete, Unparsed},
-};
+use crate::{objects::person::ApubPerson, protocol::activities::deletion::delete::Delete};
 use activitypub_federation::{core::object_id::ObjectId, deser::helpers::deserialize_one_or_many};
 use activitystreams_kinds::activity::UndoType;
 use serde::{Deserialize, Serialize};
@@ -21,6 +18,4 @@ pub struct UndoDelete {
   #[serde(deserialize_with = "deserialize_one_or_many", default)]
   #[serde(skip_serializing_if = "Vec::is_empty")]
   pub(crate) cc: Vec<Url>,
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index a600fbfba1bc65b5bc32e34b018b9b20f89d54be..ce1a1add925c29e0657b2324c952d6d5a977e230 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::community::ApubCommunity,
-  protocol::{activities::following::follow::FollowCommunity, Unparsed},
+  protocol::activities::following::follow::FollowCommunity,
 };
 use activitypub_federation::core::object_id::ObjectId;
 use activitystreams_kinds::activity::AcceptType;
@@ -15,7 +15,4 @@ pub struct AcceptFollowCommunity {
   #[serde(rename = "type")]
   pub(crate) kind: AcceptType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 2cef197d317eb70f583140617b50194596a60a26..f15010505f2f2d1fbb07e5eacc7deecb62f84a24 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-  objects::{community::ApubCommunity, person::ApubPerson},
-  protocol::Unparsed,
-};
+use crate::objects::{community::ApubCommunity, person::ApubPerson};
 use activitypub_federation::core::object_id::ObjectId;
 use activitystreams_kinds::activity::FollowType;
 use serde::{Deserialize, Serialize};
@@ -15,7 +12,4 @@ pub struct FollowCommunity {
   #[serde(rename = "type")]
   pub(crate) kind: FollowType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 38306b7c13696a9177e4935a8a255cd7dc8a3909..201601b1310c8bce615293f89959c4d24ab35d2c 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::person::ApubPerson,
-  protocol::{activities::following::follow::FollowCommunity, Unparsed},
+  protocol::activities::following::follow::FollowCommunity,
 };
 use activitypub_federation::core::object_id::ObjectId;
 use activitystreams_kinds::activity::UndoType;
@@ -15,7 +15,4 @@ pub struct UndoFollowCommunity {
   #[serde(rename = "type")]
   pub(crate) kind: UndoType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 387f3d1060ed11fdf1d4fdaf91ed2ef8fd0ebb34..ee258539fea15fc8a5cf084295eeb8314fe4bec3 100644 (file)
@@ -1,7 +1,4 @@
-use crate::{
-  objects::person::ApubPerson,
-  protocol::{activities::voting::vote::Vote, Unparsed},
-};
+use crate::{objects::person::ApubPerson, protocol::activities::voting::vote::Vote};
 use activitypub_federation::core::object_id::ObjectId;
 use activitystreams_kinds::activity::UndoType;
 use serde::{Deserialize, Serialize};
@@ -15,7 +12,4 @@ pub struct UndoVote {
   #[serde(rename = "type")]
   pub(crate) kind: UndoType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
index 6d98862ec80279af5869c502b03e51aae6536a35..002d235c0e23b3ce303da7dee6eadc6663999566 100644 (file)
@@ -1,8 +1,4 @@
-use crate::{
-  fetcher::post_or_comment::PostOrComment,
-  objects::person::ApubPerson,
-  protocol::Unparsed,
-};
+use crate::{fetcher::post_or_comment::PostOrComment, objects::person::ApubPerson};
 use activitypub_federation::core::object_id::ObjectId;
 use lemmy_utils::error::LemmyError;
 use serde::{Deserialize, Serialize};
@@ -18,9 +14,6 @@ pub struct Vote {
   #[serde(rename = "type")]
   pub(crate) kind: VoteType,
   pub(crate) id: Url,
-
-  #[serde(flatten)]
-  pub(crate) unparsed: Unparsed,
 }
 
 #[derive(Clone, Debug, Display, Deserialize, Serialize, PartialEq, Eq)]