From 7304ef32617eaaa703a92ad1d499100927ca7bbd Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 26 Nov 2024 09:37:19 +0000 Subject: [PATCH 1/2] Add note wrapper (fixes #2657) (#5221) * Add note wrapper (fixes #2657) * fix activity list * fmt * add comment * fix api tests * backwards compat * remove comment * no todo, deprecated --- Cargo.lock | 1 + crates/apub/Cargo.toml | 1 + .../{create_note.json => create_comment.json} | 0 .../create_private_message.json | 2 +- .../lemmy/objects/{note.json => comment.json} | 0 ...chat_message.json => private_message.json} | 2 +- .../mastodon/activities/private_message.json | 49 +++++++++++ .../assets/pleroma/objects/chat_message.json | 15 ---- .../apub/src/activities/community/announce.rs | 5 +- .../activities/create_or_update/comment.rs | 4 +- .../src/activities/create_or_update/mod.rs | 1 + .../create_or_update/note_wrapper.rs | 66 ++++++++++++++ .../create_or_update/private_message.rs | 6 +- crates/apub/src/activities/deletion/mod.rs | 6 +- crates/apub/src/activity_lists.rs | 82 +++++------------- crates/apub/src/objects/comment.rs | 2 +- crates/apub/src/objects/mod.rs | 1 + crates/apub/src/objects/note_wrapper.rs | 85 +++++++++++++++++++ crates/apub/src/objects/private_message.rs | 65 +++++++------- .../activities/create_or_update/mod.rs | 16 +++- .../create_or_update/note_wrapper.rs | 16 ++++ .../{chat_message.rs => private_message.rs} | 6 +- crates/apub/src/protocol/mod.rs | 1 + crates/apub/src/protocol/objects/mod.rs | 13 +-- .../apub/src/protocol/objects/note_wrapper.rs | 14 +++ .../{chat_message.rs => private_message.rs} | 11 ++- 26 files changed, 329 insertions(+), 141 deletions(-) rename crates/apub/assets/lemmy/activities/create_or_update/{create_note.json => create_comment.json} (100%) rename crates/apub/assets/lemmy/objects/{note.json => comment.json} (100%) rename crates/apub/assets/lemmy/objects/{chat_message.json => private_message.json} (93%) create mode 100644 crates/apub/assets/mastodon/activities/private_message.json delete mode 100644 crates/apub/assets/pleroma/objects/chat_message.json create mode 100644 crates/apub/src/activities/create_or_update/note_wrapper.rs create mode 100644 crates/apub/src/objects/note_wrapper.rs create mode 100644 crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs rename crates/apub/src/protocol/activities/create_or_update/{chat_message.rs => private_message.rs} (75%) create mode 100644 crates/apub/src/protocol/objects/note_wrapper.rs rename crates/apub/src/protocol/objects/{chat_message.rs => private_message.rs} (79%) diff --git a/Cargo.lock b/Cargo.lock index fa63a4b27..669626caa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2582,6 +2582,7 @@ dependencies = [ "moka", "pretty_assertions", "reqwest 0.12.8", + "semver", "serde", "serde_json", "serde_with", diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index 057e9bd38..8124fda01 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -45,6 +45,7 @@ html2md = "0.2.14" html2text = "0.12.6" stringreader = "0.1.1" enum_delegate = "0.2.0" +semver = "1.0.23" [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/apub/assets/lemmy/activities/create_or_update/create_note.json b/crates/apub/assets/lemmy/activities/create_or_update/create_comment.json similarity index 100% rename from crates/apub/assets/lemmy/activities/create_or_update/create_note.json rename to crates/apub/assets/lemmy/activities/create_or_update/create_comment.json diff --git a/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json b/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json index 54ee39350..e7dbdd0f9 100644 --- a/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json +++ b/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json @@ -3,7 +3,7 @@ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta", "to": ["http://ds9.lemmy.ml/u/lemmy_alpha"], "object": { - "type": "ChatMessage", + "type": "Note", "id": "http://enterprise.lemmy.ml/private_message/1", "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta", "to": ["http://ds9.lemmy.ml/u/lemmy_alpha"], diff --git a/crates/apub/assets/lemmy/objects/note.json b/crates/apub/assets/lemmy/objects/comment.json similarity index 100% rename from crates/apub/assets/lemmy/objects/note.json rename to crates/apub/assets/lemmy/objects/comment.json diff --git a/crates/apub/assets/lemmy/objects/chat_message.json b/crates/apub/assets/lemmy/objects/private_message.json similarity index 93% rename from crates/apub/assets/lemmy/objects/chat_message.json rename to crates/apub/assets/lemmy/objects/private_message.json index 95b37322e..a3579523e 100644 --- a/crates/apub/assets/lemmy/objects/chat_message.json +++ b/crates/apub/assets/lemmy/objects/private_message.json @@ -1,6 +1,6 @@ { "id": "https://enterprise.lemmy.ml/private_message/1621", - "type": "ChatMessage", + "type": "Note", "attributedTo": "https://enterprise.lemmy.ml/u/picard", "to": ["https://queer.hacktivis.me/users/lanodan"], "content": "

Hello hello, testing

\n", diff --git a/crates/apub/assets/mastodon/activities/private_message.json b/crates/apub/assets/mastodon/activities/private_message.json new file mode 100644 index 000000000..b542859b5 --- /dev/null +++ b/crates/apub/assets/mastodon/activities/private_message.json @@ -0,0 +1,49 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "ostatus": "http://ostatus.org#", + "atomUri": "ostatus:atomUri", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "votersCount": "toot:votersCount" + } + ], + "id": "https://mastodon.world/users/nutomic/statuses/110854468010322301", + "type": "Note", + "summary": null, + "inReplyTo": "https://mastodon.world/users/nutomic/statuses/110854464248188528", + "published": "2023-08-08T14:29:04Z", + "url": "https://mastodon.world/@nutomic/110854468010322301", + "attributedTo": "https://mastodon.world/users/nutomic", + "to": ["https://ds9.lemmy.ml/u/nutomic"], + "cc": [], + "sensitive": false, + "atomUri": "https://mastodon.world/users/nutomic/statuses/110854468010322301", + "inReplyToAtomUri": "https://mastodon.world/users/nutomic/statuses/110854464248188528", + "conversation": "tag:mastodon.world,2023-08-08:objectId=121377096:objectType=Conversation", + "content": "

@nutomic@ds9.lemmy.ml 444

", + "contentMap": { + "es": "

@nutomic@ds9.lemmy.ml 444

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "https://ds9.lemmy.ml/u/nutomic", + "name": "@nutomic@ds9.lemmy.ml" + } + ], + "replies": { + "id": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies?only_other_accounts=true&page=true", + "partOf": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies", + "items": [] + } + } +} diff --git a/crates/apub/assets/pleroma/objects/chat_message.json b/crates/apub/assets/pleroma/objects/chat_message.json deleted file mode 100644 index 6a2afc82e..000000000 --- a/crates/apub/assets/pleroma/objects/chat_message.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://queer.hacktivis.me/schemas/litepub-0.1.jsonld", - { - "@language": "und" - } - ], - "attributedTo": "https://queer.hacktivis.me/users/lanodan", - "content": "Hi!", - "id": "https://queer.hacktivis.me/objects/2", - "published": "2020-02-12T14:08:20Z", - "to": ["https://enterprise.lemmy.ml/u/picard"], - "type": "ChatMessage" -} diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 950f4861d..9d714e304 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -64,16 +64,17 @@ impl ActivityHandler for RawAnnouncableActivities { // verify and receive activity activity.verify(context).await?; - activity.clone().receive(context).await?; + let actor_id = activity.actor().clone().into(); + activity.receive(context).await?; // if community is local, send activity to followers if let Some(community) = community { if community.local { - let actor_id = activity.actor().clone().into(); verify_person_in_community(&actor_id, &community, context).await?; AnnounceActivity::send(self, &community, context).await?; } } + Ok(()) } } diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 9f64e805b..93cac92ee 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -43,6 +43,7 @@ use lemmy_utils::{ error::{LemmyError, LemmyResult}, utils::mention::scrape_text_for_mentions, }; +use serde_json::{from_value, to_value}; use url::Url; impl CreateOrUpdateNote { @@ -98,7 +99,8 @@ impl CreateOrUpdateNote { inboxes.add_inbox(person.shared_inbox_or_inbox()); } - let activity = AnnouncableActivities::CreateOrUpdateComment(create_or_update); + let activity = + AnnouncableActivities::CreateOrUpdateNoteWrapper(from_value(to_value(create_or_update)?)?); send_activity_in_community(activity, &person, &community, inboxes, false, &context).await } } diff --git a/crates/apub/src/activities/create_or_update/mod.rs b/crates/apub/src/activities/create_or_update/mod.rs index c69e00e91..b442e5fa3 100644 --- a/crates/apub/src/activities/create_or_update/mod.rs +++ b/crates/apub/src/activities/create_or_update/mod.rs @@ -1,3 +1,4 @@ pub mod comment; +pub(crate) mod note_wrapper; pub mod post; pub mod private_message; diff --git a/crates/apub/src/activities/create_or_update/note_wrapper.rs b/crates/apub/src/activities/create_or_update/note_wrapper.rs new file mode 100644 index 000000000..9206d0c05 --- /dev/null +++ b/crates/apub/src/activities/create_or_update/note_wrapper.rs @@ -0,0 +1,66 @@ +use crate::{ + objects::{community::ApubCommunity, note_wrapper::is_public}, + protocol::{ + activities::create_or_update::{ + note::CreateOrUpdateNote, + note_wrapper::CreateOrUpdateNoteWrapper, + private_message::CreateOrUpdatePrivateMessage, + }, + InCommunity, + }, +}; +use activitypub_federation::{config::Data, traits::ActivityHandler}; +use lemmy_api_common::context::LemmyContext; +use lemmy_utils::error::{FederationError, LemmyError, LemmyResult}; +use serde_json::{from_value, to_value}; +use url::Url; + +#[async_trait::async_trait] +impl ActivityHandler for CreateOrUpdateNoteWrapper { + 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, context: &Data) -> LemmyResult<()> { + let val = to_value(self)?; + if is_public(&self.to, &self.cc) { + CreateOrUpdateNote::verify(&from_value(val)?, context).await?; + } else { + CreateOrUpdatePrivateMessage::verify(&from_value(val)?, context).await?; + } + Ok(()) + } + + #[tracing::instrument(skip_all)] + async fn receive(self, context: &Data) -> LemmyResult<()> { + let is_public = is_public(&self.to, &self.cc); + let val = to_value(self)?; + if is_public { + CreateOrUpdateNote::receive(from_value(val)?, context).await?; + } else { + CreateOrUpdatePrivateMessage::receive(from_value(val)?, context).await?; + } + Ok(()) + } +} + +#[async_trait::async_trait] +impl InCommunity for CreateOrUpdateNoteWrapper { + #[tracing::instrument(skip(self, context))] + async fn community(&self, context: &Data) -> LemmyResult { + if is_public(&self.to, &self.cc) { + let comment: CreateOrUpdateNote = from_value(to_value(self)?)?; + comment.community(context).await + } else { + Err(FederationError::ObjectIsNotPublic.into()) + } + } +} diff --git a/crates/apub/src/activities/create_or_update/private_message.rs b/crates/apub/src/activities/create_or_update/private_message.rs index 6bba4e374..b6e7478ef 100644 --- a/crates/apub/src/activities/create_or_update/private_message.rs +++ b/crates/apub/src/activities/create_or_update/private_message.rs @@ -3,7 +3,7 @@ use crate::{ insert_received_activity, objects::{person::ApubPerson, private_message::ApubPrivateMessage}, protocol::activities::{ - create_or_update::chat_message::CreateOrUpdateChatMessage, + create_or_update::private_message::CreateOrUpdatePrivateMessage, CreateOrUpdateType, }, }; @@ -30,7 +30,7 @@ pub(crate) async fn send_create_or_update_pm( kind.clone(), &context.settings().get_protocol_and_hostname(), )?; - let create_or_update = CreateOrUpdateChatMessage { + let create_or_update = CreateOrUpdatePrivateMessage { id: id.clone(), actor: actor.id().into(), to: [recipient.id().into()], @@ -44,7 +44,7 @@ pub(crate) async fn send_create_or_update_pm( } #[async_trait::async_trait] -impl ActivityHandler for CreateOrUpdateChatMessage { +impl ActivityHandler for CreateOrUpdatePrivateMessage { type DataType = LemmyContext; type Error = LemmyError; diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index 15118a476..941ac4237 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -36,7 +36,7 @@ use lemmy_db_schema::{ community::{Community, CommunityUpdateForm}, person::Person, post::{Post, PostUpdateForm}, - private_message::{PrivateMessage, PrivateMessageUpdateForm}, + private_message::{PrivateMessage as DbPrivateMessage, PrivateMessageUpdateForm}, }, traits::Crud, }; @@ -82,7 +82,7 @@ pub(crate) async fn send_apub_delete_in_community( #[tracing::instrument(skip_all)] pub(crate) async fn send_apub_delete_private_message( actor: &ApubPerson, - pm: PrivateMessage, + pm: DbPrivateMessage, deleted: bool, context: Data, ) -> LemmyResult<()> { @@ -298,7 +298,7 @@ async fn receive_delete_action( } } DeletableObjects::PrivateMessage(pm) => { - PrivateMessage::update( + DbPrivateMessage::update( &mut context.pool(), pm.id, &PrivateMessageUpdateForm { diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index 7ed1d8baf..0a11e30a0 100644 --- a/crates/apub/src/activity_lists.rs +++ b/crates/apub/src/activity_lists.rs @@ -11,11 +11,7 @@ use crate::{ report::Report, update::UpdateCommunity, }, - create_or_update::{ - chat_message::CreateOrUpdateChatMessage, - note::CreateOrUpdateNote, - page::CreateOrUpdatePage, - }, + create_or_update::{note_wrapper::CreateOrUpdateNoteWrapper, page::CreateOrUpdatePage}, deletion::{delete::Delete, undo_delete::UndoDelete}, following::{ accept::AcceptFollow, @@ -48,47 +44,17 @@ pub enum SharedInboxActivities { AcceptFollow(AcceptFollow), RejectFollow(RejectFollow), UndoFollow(UndoFollow), - CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage), Report(Report), AnnounceActivity(AnnounceActivity), /// This is a catch-all and needs to be last RawAnnouncableActivities(RawAnnouncableActivities), } -/// List of activities which the group inbox can handle. -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -#[enum_delegate::implement(ActivityHandler)] -pub enum GroupInboxActivities { - Follow(Follow), - UndoFollow(UndoFollow), - Report(Report), - /// This is a catch-all and needs to be last - AnnouncableActivities(RawAnnouncableActivities), -} - -/// List of activities which the person inbox can handle. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(untagged)] -#[enum_delegate::implement(ActivityHandler)] -pub enum PersonInboxActivities { - Follow(Follow), - AcceptFollow(AcceptFollow), - RejectFollow(RejectFollow), - UndoFollow(UndoFollow), - CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage), - Delete(Delete), - UndoDelete(UndoDelete), - AnnounceActivity(AnnounceActivity), - /// User can also receive some "announcable" activities, eg a comment mention. - AnnouncableActivities(AnnouncableActivities), -} - #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(untagged)] #[enum_delegate::implement(ActivityHandler)] pub enum AnnouncableActivities { - CreateOrUpdateComment(CreateOrUpdateNote), + CreateOrUpdateNoteWrapper(CreateOrUpdateNoteWrapper), CreateOrUpdatePost(CreateOrUpdatePage), Vote(Vote), UndoVote(UndoVote), @@ -111,7 +77,7 @@ impl InCommunity for AnnouncableActivities { async fn community(&self, context: &Data) -> LemmyResult { use AnnouncableActivities::*; match self { - CreateOrUpdateComment(a) => a.community(context).await, + CreateOrUpdateNoteWrapper(a) => a.community(context).await, CreateOrUpdatePost(a) => a.community(context).await, Vote(a) => a.community(context).await, UndoVote(a) => a.community(context).await, @@ -133,40 +99,32 @@ impl InCommunity for AnnouncableActivities { mod tests { use crate::{ - activity_lists::{GroupInboxActivities, PersonInboxActivities, SharedInboxActivities}, + activity_lists::SharedInboxActivities, protocol::tests::{test_json, test_parse_lemmy_item}, }; use lemmy_utils::error::LemmyResult; - #[test] - fn test_group_inbox() -> LemmyResult<()> { - test_parse_lemmy_item::("assets/lemmy/activities/following/follow.json")?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_note.json", - )?; - Ok(()) - } - - #[test] - fn test_person_inbox() -> LemmyResult<()> { - test_parse_lemmy_item::( - "assets/lemmy/activities/following/accept.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_note.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_private_message.json", - )?; - test_json::("assets/mastodon/activities/follow.json")?; - Ok(()) - } - #[test] fn test_shared_inbox() -> LemmyResult<()> { test_parse_lemmy_item::( "assets/lemmy/activities/deletion/delete_user.json", )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/following/accept.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_comment.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_private_message.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/following/follow.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_comment.json", + )?; + test_json::("assets/mastodon/activities/follow.json")?; Ok(()) } } diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index dc0721404..2c8ed9f9d 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -266,7 +266,7 @@ pub(crate) mod tests { let url = Url::parse("https://enterprise.lemmy.ml/comment/38741")?; let data = prepare_comment_test(&url, &context).await?; - let json: Note = file_to_json_object("assets/lemmy/objects/note.json")?; + let json: Note = file_to_json_object("assets/lemmy/objects/comment.json")?; ApubComment::verify(&json, &url, &context).await?; let comment = ApubComment::from_json(json.clone(), &context).await?; diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index f837f7ad3..58841b29e 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -15,6 +15,7 @@ use std::fmt::Debug; pub mod comment; pub mod community; pub mod instance; +pub mod note_wrapper; pub mod person; pub mod post; pub mod private_message; diff --git a/crates/apub/src/objects/note_wrapper.rs b/crates/apub/src/objects/note_wrapper.rs new file mode 100644 index 000000000..5d613c7ae --- /dev/null +++ b/crates/apub/src/objects/note_wrapper.rs @@ -0,0 +1,85 @@ +use super::comment::ApubComment; +use crate::{ + objects::private_message::ApubPrivateMessage, + protocol::objects::note_wrapper::NoteWrapper, +}; +use activitypub_federation::{config::Data, kinds::public, traits::Object}; +use chrono::{DateTime, Utc}; +use lemmy_api_common::{context::LemmyContext, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyResult}; +use serde_json::{from_value, to_value}; +use url::Url; + +/// Private messages and public comments are quite awkward in Activitypub, because the json +/// format looks identical. They only way to differentiate them is to check for the presence +/// or absence of `https://www.w3.org/ns/activitystreams#Public` in `to` or `cc` which this +/// wrapper does. +#[derive(Debug)] +pub(crate) struct ApubNote {} + +#[async_trait::async_trait] +impl Object for ApubNote { + type DataType = LemmyContext; + type Kind = NoteWrapper; + type Error = LemmyError; + + fn last_refreshed_at(&self) -> Option> { + None + } + + #[tracing::instrument(skip_all)] + async fn read_from_id( + _object_id: Url, + _context: &Data, + ) -> LemmyResult> { + Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) + } + + #[tracing::instrument(skip_all)] + async fn delete(self, _context: &Data) -> LemmyResult<()> { + Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) + } + + async fn verify( + note: &NoteWrapper, + expected_domain: &Url, + context: &Data, + ) -> LemmyResult<()> { + let val = to_value(note)?; + if is_public(¬e.to, ¬e.cc) { + ApubComment::verify(&from_value(val)?, expected_domain, context).await?; + } else { + ApubPrivateMessage::verify(&from_value(val)?, expected_domain, context).await?; + } + Ok(()) + } + + async fn from_json(note: NoteWrapper, context: &Data) -> LemmyResult { + let is_public = is_public(¬e.to, ¬e.cc); + let val = to_value(note)?; + if is_public { + ApubComment::from_json(from_value(val)?, context).await?; + } else { + ApubPrivateMessage::from_json(from_value(val)?, context).await?; + } + Ok(ApubNote {}) + } + + async fn into_json(self, _context: &Data) -> LemmyResult { + Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) + } +} + +pub(crate) fn is_public(to: &Option>, cc: &Option>) -> bool { + if let Some(to) = to { + if to.contains(&public()) { + return true; + } + } + if let Some(cc) = cc { + if cc.contains(&public()) { + return true; + } + } + false +} diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 9ada5f657..ba64bd593 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -4,7 +4,7 @@ use crate::{ fetcher::markdown_links::markdown_rewrite_remote_links, objects::read_from_string_or_source, protocol::{ - objects::chat_message::{ChatMessage, ChatMessageType}, + objects::private_message::{PrivateMessage, PrivateMessageType}, Source, }, }; @@ -25,10 +25,11 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ source::{ + instance::Instance, local_site::LocalSite, person::Person, person_block::PersonBlock, - private_message::{PrivateMessage, PrivateMessageInsertForm}, + private_message::{PrivateMessage as DbPrivateMessage, PrivateMessageInsertForm}, }, traits::Crud, }; @@ -37,21 +38,22 @@ use lemmy_utils::{ error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::markdown_to_html, }; +use semver::{Version, VersionReq}; use std::ops::Deref; use url::Url; #[derive(Clone, Debug)] -pub struct ApubPrivateMessage(pub(crate) PrivateMessage); +pub struct ApubPrivateMessage(pub(crate) DbPrivateMessage); impl Deref for ApubPrivateMessage { - type Target = PrivateMessage; + type Target = DbPrivateMessage; fn deref(&self) -> &Self::Target { &self.0 } } -impl From for ApubPrivateMessage { - fn from(pm: PrivateMessage) -> Self { +impl From for ApubPrivateMessage { + fn from(pm: DbPrivateMessage) -> Self { ApubPrivateMessage(pm) } } @@ -59,7 +61,7 @@ impl From for ApubPrivateMessage { #[async_trait::async_trait] impl Object for ApubPrivateMessage { type DataType = LemmyContext; - type Kind = ChatMessage; + type Kind = PrivateMessage; type Error = LemmyError; fn last_refreshed_at(&self) -> Option> { @@ -72,7 +74,7 @@ impl Object for ApubPrivateMessage { context: &Data, ) -> LemmyResult> { Ok( - PrivateMessage::read_from_apub_id(&mut context.pool(), object_id) + DbPrivateMessage::read_from_apub_id(&mut context.pool(), object_id) .await? .map(Into::into), ) @@ -84,15 +86,26 @@ impl Object for ApubPrivateMessage { } #[tracing::instrument(skip_all)] - async fn into_json(self, context: &Data) -> LemmyResult { + async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; let creator = Person::read(&mut context.pool(), creator_id).await?; let recipient_id = self.recipient_id; let recipient = Person::read(&mut context.pool(), recipient_id).await?; - let note = ChatMessage { - r#type: ChatMessageType::ChatMessage, + let instance = Instance::read(&mut context.pool(), recipient.instance_id).await?; + let mut kind = PrivateMessageType::Note; + + // Deprecated: For Lemmy versions before 0.20, send private messages with old type + if let (Some(software), Some(version)) = (instance.software, &instance.version) { + let req = VersionReq::parse("<0.20")?; + if software == "lemmy" && req.matches(&Version::parse(version)?) { + kind = PrivateMessageType::ChatMessage + } + } + + let note = PrivateMessage { + kind, id: self.ap_id.clone().into(), attributed_to: creator.actor_id.into(), to: [recipient.actor_id.into()], @@ -107,7 +120,7 @@ impl Object for ApubPrivateMessage { #[tracing::instrument(skip_all)] async fn verify( - note: &ChatMessage, + note: &PrivateMessage, expected_domain: &Url, context: &Data, ) -> LemmyResult<()> { @@ -128,7 +141,7 @@ impl Object for ApubPrivateMessage { #[tracing::instrument(skip_all)] async fn from_json( - note: ChatMessage, + note: PrivateMessage, context: &Data, ) -> LemmyResult { let creator = note.attributed_to.dereference(context).await?; @@ -161,7 +174,7 @@ impl Object for ApubPrivateMessage { local: Some(false), }; let timestamp = note.updated.or(note.published).unwrap_or_else(Utc::now); - let pm = PrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?; + let pm = DbPrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?; Ok(pm.into()) } } @@ -213,7 +226,7 @@ mod tests { let context = LemmyContext::init_test_context().await; let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?; let data = prepare_comment_test(&url, &context).await?; - let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json")?; + let json: PrivateMessage = file_to_json_object("assets/lemmy/objects/private_message.json")?; ApubPrivateMessage::verify(&json, &url, &context).await?; let pm = ApubPrivateMessage::from_json(json.clone(), &context).await?; @@ -225,27 +238,7 @@ mod tests { let to_apub = pm.into_json(&context).await?; assert_json_include!(actual: json, expected: to_apub); - PrivateMessage::delete(&mut context.pool(), pm_id).await?; - cleanup(data, &context).await?; - Ok(()) - } - - #[tokio::test] - #[serial] - async fn test_parse_pleroma_pm() -> LemmyResult<()> { - let context = LemmyContext::init_test_context().await; - let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?; - let data = prepare_comment_test(&url, &context).await?; - let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2")?; - let json = file_to_json_object("assets/pleroma/objects/chat_message.json")?; - ApubPrivateMessage::verify(&json, &pleroma_url, &context).await?; - let pm = ApubPrivateMessage::from_json(json, &context).await?; - - assert_eq!(pm.ap_id, pleroma_url.into()); - assert_eq!(pm.content.len(), 3); - assert_eq!(context.request_count(), 0); - - PrivateMessage::delete(&mut context.pool(), pm.id).await?; + DbPrivateMessage::delete(&mut context.pool(), pm_id).await?; cleanup(data, &context).await?; Ok(()) } diff --git a/crates/apub/src/protocol/activities/create_or_update/mod.rs b/crates/apub/src/protocol/activities/create_or_update/mod.rs index 3d9dbbb1d..d34be93c8 100644 --- a/crates/apub/src/protocol/activities/create_or_update/mod.rs +++ b/crates/apub/src/protocol/activities/create_or_update/mod.rs @@ -1,14 +1,16 @@ -pub mod chat_message; pub mod note; +pub(crate) mod note_wrapper; pub mod page; +pub mod private_message; #[cfg(test)] mod tests { + use super::note_wrapper::CreateOrUpdateNoteWrapper; use crate::protocol::{ activities::create_or_update::{ - chat_message::CreateOrUpdateChatMessage, note::CreateOrUpdateNote, page::CreateOrUpdatePage, + private_message::CreateOrUpdatePrivateMessage, }, tests::test_parse_lemmy_item, }; @@ -23,9 +25,15 @@ mod tests { "assets/lemmy/activities/create_or_update/update_page.json", )?; test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_note.json", + "assets/lemmy/activities/create_or_update/create_comment.json", )?; - test_parse_lemmy_item::( + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_private_message.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_comment.json", + )?; + test_parse_lemmy_item::( "assets/lemmy/activities/create_or_update/create_private_message.json", )?; Ok(()) diff --git a/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs b/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs new file mode 100644 index 000000000..bc53c80fd --- /dev/null +++ b/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs @@ -0,0 +1,16 @@ +use crate::protocol::objects::note_wrapper::NoteWrapper; +use serde::{Deserialize, Serialize}; +use serde_json::{Map, Value}; +use url::Url; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateOrUpdateNoteWrapper { + object: NoteWrapper, + pub(crate) id: Url, + pub(crate) actor: Url, + pub(crate) to: Option>, + pub(crate) cc: Option>, + #[serde(flatten)] + other: Map, +} diff --git a/crates/apub/src/protocol/activities/create_or_update/chat_message.rs b/crates/apub/src/protocol/activities/create_or_update/private_message.rs similarity index 75% rename from crates/apub/src/protocol/activities/create_or_update/chat_message.rs rename to crates/apub/src/protocol/activities/create_or_update/private_message.rs index 30e94a28d..0c08f3991 100644 --- a/crates/apub/src/protocol/activities/create_or_update/chat_message.rs +++ b/crates/apub/src/protocol/activities/create_or_update/private_message.rs @@ -1,6 +1,6 @@ use crate::{ objects::person::ApubPerson, - protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage}, + protocol::{activities::CreateOrUpdateType, objects::private_message::PrivateMessage}, }; use activitypub_federation::{fetch::object_id::ObjectId, protocol::helpers::deserialize_one}; use serde::{Deserialize, Serialize}; @@ -8,12 +8,12 @@ use url::Url; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct CreateOrUpdateChatMessage { +pub struct CreateOrUpdatePrivateMessage { pub(crate) id: Url, pub(crate) actor: ObjectId, #[serde(deserialize_with = "deserialize_one")] pub(crate) to: [ObjectId; 1], - pub(crate) object: ChatMessage, + pub(crate) object: PrivateMessage, #[serde(rename = "type")] pub(crate) kind: CreateOrUpdateType, } diff --git a/crates/apub/src/protocol/mod.rs b/crates/apub/src/protocol/mod.rs index a4774ac1d..9f218e351 100644 --- a/crates/apub/src/protocol/mod.rs +++ b/crates/apub/src/protocol/mod.rs @@ -116,6 +116,7 @@ pub(crate) mod tests { // parse file into hashmap, which ensures that every field is included let raw = file_to_json_object::>(path)?; // assert that all fields are identical, otherwise print diff + //dbg!(&parsed, &raw); assert_json_include!(actual: &parsed, expected: raw); Ok(parsed) } diff --git a/crates/apub/src/protocol/objects/mod.rs b/crates/apub/src/protocol/objects/mod.rs index 00fe26d2b..757f49ae4 100644 --- a/crates/apub/src/protocol/objects/mod.rs +++ b/crates/apub/src/protocol/objects/mod.rs @@ -8,12 +8,13 @@ use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; -pub(crate) mod chat_message; pub(crate) mod group; pub(crate) mod instance; pub(crate) mod note; +pub(crate) mod note_wrapper; pub(crate) mod page; pub(crate) mod person; +pub(crate) mod private_message; pub(crate) mod tombstone; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] @@ -101,14 +102,15 @@ impl LanguageTag { #[cfg(test)] mod tests { + use super::note_wrapper::NoteWrapper; use crate::protocol::{ objects::{ - chat_message::ChatMessage, group::Group, instance::Instance, note::Note, page::Page, person::Person, + private_message::PrivateMessage, tombstone::Tombstone, }, tests::{test_json, test_parse_lemmy_item}, @@ -121,8 +123,10 @@ mod tests { test_parse_lemmy_item::("assets/lemmy/objects/group.json")?; test_parse_lemmy_item::("assets/lemmy/objects/person.json")?; test_parse_lemmy_item::("assets/lemmy/objects/page.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/note.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/chat_message.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/comment.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/private_message.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/comment.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/private_message.json")?; test_parse_lemmy_item::("assets/lemmy/objects/tombstone.json")?; Ok(()) } @@ -131,7 +135,6 @@ mod tests { fn test_parse_objects_pleroma() -> LemmyResult<()> { test_json::("assets/pleroma/objects/person.json")?; test_json::("assets/pleroma/objects/note.json")?; - test_json::("assets/pleroma/objects/chat_message.json")?; Ok(()) } diff --git a/crates/apub/src/protocol/objects/note_wrapper.rs b/crates/apub/src/protocol/objects/note_wrapper.rs new file mode 100644 index 000000000..f1bcf605b --- /dev/null +++ b/crates/apub/src/protocol/objects/note_wrapper.rs @@ -0,0 +1,14 @@ +use activitypub_federation::kinds::object::NoteType; +use serde::{Deserialize, Serialize}; +use serde_json::{Map, Value}; +use url::Url; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct NoteWrapper { + pub(crate) r#type: NoteType, + pub(crate) to: Option>, + pub(crate) cc: Option>, + #[serde(flatten)] + other: Map, +} diff --git a/crates/apub/src/protocol/objects/chat_message.rs b/crates/apub/src/protocol/objects/private_message.rs similarity index 79% rename from crates/apub/src/protocol/objects/chat_message.rs rename to crates/apub/src/protocol/objects/private_message.rs index 8cb83e664..bf7fe90cb 100644 --- a/crates/apub/src/protocol/objects/chat_message.rs +++ b/crates/apub/src/protocol/objects/private_message.rs @@ -16,8 +16,9 @@ use serde_with::skip_serializing_none; #[skip_serializing_none] #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct ChatMessage { - pub(crate) r#type: ChatMessageType, +pub struct PrivateMessage { + #[serde(rename = "type")] + pub(crate) kind: PrivateMessageType, pub(crate) id: ObjectId, pub(crate) attributed_to: ObjectId, #[serde(deserialize_with = "deserialize_one")] @@ -31,8 +32,10 @@ pub struct ChatMessage { pub(crate) updated: Option>, } -/// https://docs.pleroma.social/backend/development/ap_extensions/#chatmessages #[derive(Clone, Debug, Deserialize, Serialize)] -pub enum ChatMessageType { +pub enum PrivateMessageType { + /// For compatibility with Lemmy 0.19 and earlier + /// https://docs.pleroma.social/backend/development/ap_extensions/#chatmessages ChatMessage, + Note, } From 5a403bc250d2662344265c4e0d000aea62325035 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 28 Nov 2024 11:14:04 +0100 Subject: [PATCH 2/2] Revert " Add note wrapper (fixes #2657) (#5221)" This reverts commit 7304ef32617eaaa703a92ad1d499100927ca7bbd. --- Cargo.lock | 1 - crates/apub/Cargo.toml | 1 - .../{create_comment.json => create_note.json} | 0 .../create_private_message.json | 2 +- ...private_message.json => chat_message.json} | 2 +- .../lemmy/objects/{comment.json => note.json} | 0 .../mastodon/activities/private_message.json | 49 ----------- .../assets/pleroma/objects/chat_message.json | 15 ++++ .../apub/src/activities/community/announce.rs | 5 +- .../activities/create_or_update/comment.rs | 4 +- .../src/activities/create_or_update/mod.rs | 1 - .../create_or_update/note_wrapper.rs | 66 -------------- .../create_or_update/private_message.rs | 6 +- crates/apub/src/activities/deletion/mod.rs | 6 +- crates/apub/src/activity_lists.rs | 82 +++++++++++++----- crates/apub/src/objects/comment.rs | 2 +- crates/apub/src/objects/mod.rs | 1 - crates/apub/src/objects/note_wrapper.rs | 85 ------------------- crates/apub/src/objects/private_message.rs | 65 +++++++------- .../{private_message.rs => chat_message.rs} | 6 +- .../activities/create_or_update/mod.rs | 16 +--- .../create_or_update/note_wrapper.rs | 16 ---- crates/apub/src/protocol/mod.rs | 1 - .../{private_message.rs => chat_message.rs} | 11 +-- crates/apub/src/protocol/objects/mod.rs | 13 ++- .../apub/src/protocol/objects/note_wrapper.rs | 14 --- 26 files changed, 141 insertions(+), 329 deletions(-) rename crates/apub/assets/lemmy/activities/create_or_update/{create_comment.json => create_note.json} (100%) rename crates/apub/assets/lemmy/objects/{private_message.json => chat_message.json} (93%) rename crates/apub/assets/lemmy/objects/{comment.json => note.json} (100%) delete mode 100644 crates/apub/assets/mastodon/activities/private_message.json create mode 100644 crates/apub/assets/pleroma/objects/chat_message.json delete mode 100644 crates/apub/src/activities/create_or_update/note_wrapper.rs delete mode 100644 crates/apub/src/objects/note_wrapper.rs rename crates/apub/src/protocol/activities/create_or_update/{private_message.rs => chat_message.rs} (75%) delete mode 100644 crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs rename crates/apub/src/protocol/objects/{private_message.rs => chat_message.rs} (79%) delete mode 100644 crates/apub/src/protocol/objects/note_wrapper.rs diff --git a/Cargo.lock b/Cargo.lock index 669626caa..fa63a4b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2582,7 +2582,6 @@ dependencies = [ "moka", "pretty_assertions", "reqwest 0.12.8", - "semver", "serde", "serde_json", "serde_with", diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index 8124fda01..057e9bd38 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -45,7 +45,6 @@ html2md = "0.2.14" html2text = "0.12.6" stringreader = "0.1.1" enum_delegate = "0.2.0" -semver = "1.0.23" [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/apub/assets/lemmy/activities/create_or_update/create_comment.json b/crates/apub/assets/lemmy/activities/create_or_update/create_note.json similarity index 100% rename from crates/apub/assets/lemmy/activities/create_or_update/create_comment.json rename to crates/apub/assets/lemmy/activities/create_or_update/create_note.json diff --git a/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json b/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json index e7dbdd0f9..54ee39350 100644 --- a/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json +++ b/crates/apub/assets/lemmy/activities/create_or_update/create_private_message.json @@ -3,7 +3,7 @@ "actor": "http://enterprise.lemmy.ml/u/lemmy_beta", "to": ["http://ds9.lemmy.ml/u/lemmy_alpha"], "object": { - "type": "Note", + "type": "ChatMessage", "id": "http://enterprise.lemmy.ml/private_message/1", "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta", "to": ["http://ds9.lemmy.ml/u/lemmy_alpha"], diff --git a/crates/apub/assets/lemmy/objects/private_message.json b/crates/apub/assets/lemmy/objects/chat_message.json similarity index 93% rename from crates/apub/assets/lemmy/objects/private_message.json rename to crates/apub/assets/lemmy/objects/chat_message.json index a3579523e..95b37322e 100644 --- a/crates/apub/assets/lemmy/objects/private_message.json +++ b/crates/apub/assets/lemmy/objects/chat_message.json @@ -1,6 +1,6 @@ { "id": "https://enterprise.lemmy.ml/private_message/1621", - "type": "Note", + "type": "ChatMessage", "attributedTo": "https://enterprise.lemmy.ml/u/picard", "to": ["https://queer.hacktivis.me/users/lanodan"], "content": "

Hello hello, testing

\n", diff --git a/crates/apub/assets/lemmy/objects/comment.json b/crates/apub/assets/lemmy/objects/note.json similarity index 100% rename from crates/apub/assets/lemmy/objects/comment.json rename to crates/apub/assets/lemmy/objects/note.json diff --git a/crates/apub/assets/mastodon/activities/private_message.json b/crates/apub/assets/mastodon/activities/private_message.json deleted file mode 100644 index b542859b5..000000000 --- a/crates/apub/assets/mastodon/activities/private_message.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - { - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "sensitive": "as:sensitive", - "toot": "http://joinmastodon.org/ns#", - "votersCount": "toot:votersCount" - } - ], - "id": "https://mastodon.world/users/nutomic/statuses/110854468010322301", - "type": "Note", - "summary": null, - "inReplyTo": "https://mastodon.world/users/nutomic/statuses/110854464248188528", - "published": "2023-08-08T14:29:04Z", - "url": "https://mastodon.world/@nutomic/110854468010322301", - "attributedTo": "https://mastodon.world/users/nutomic", - "to": ["https://ds9.lemmy.ml/u/nutomic"], - "cc": [], - "sensitive": false, - "atomUri": "https://mastodon.world/users/nutomic/statuses/110854468010322301", - "inReplyToAtomUri": "https://mastodon.world/users/nutomic/statuses/110854464248188528", - "conversation": "tag:mastodon.world,2023-08-08:objectId=121377096:objectType=Conversation", - "content": "

@nutomic@ds9.lemmy.ml 444

", - "contentMap": { - "es": "

@nutomic@ds9.lemmy.ml 444

" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "https://ds9.lemmy.ml/u/nutomic", - "name": "@nutomic@ds9.lemmy.ml" - } - ], - "replies": { - "id": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies", - "type": "Collection", - "first": { - "type": "CollectionPage", - "next": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies?only_other_accounts=true&page=true", - "partOf": "https://mastodon.world/users/nutomic/statuses/110854468010322301/replies", - "items": [] - } - } -} diff --git a/crates/apub/assets/pleroma/objects/chat_message.json b/crates/apub/assets/pleroma/objects/chat_message.json new file mode 100644 index 000000000..6a2afc82e --- /dev/null +++ b/crates/apub/assets/pleroma/objects/chat_message.json @@ -0,0 +1,15 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://queer.hacktivis.me/schemas/litepub-0.1.jsonld", + { + "@language": "und" + } + ], + "attributedTo": "https://queer.hacktivis.me/users/lanodan", + "content": "Hi!", + "id": "https://queer.hacktivis.me/objects/2", + "published": "2020-02-12T14:08:20Z", + "to": ["https://enterprise.lemmy.ml/u/picard"], + "type": "ChatMessage" +} diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 9d714e304..950f4861d 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -64,17 +64,16 @@ impl ActivityHandler for RawAnnouncableActivities { // verify and receive activity activity.verify(context).await?; - let actor_id = activity.actor().clone().into(); - activity.receive(context).await?; + activity.clone().receive(context).await?; // if community is local, send activity to followers if let Some(community) = community { if community.local { + let actor_id = activity.actor().clone().into(); verify_person_in_community(&actor_id, &community, context).await?; AnnounceActivity::send(self, &community, context).await?; } } - Ok(()) } } diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 93cac92ee..9f64e805b 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -43,7 +43,6 @@ use lemmy_utils::{ error::{LemmyError, LemmyResult}, utils::mention::scrape_text_for_mentions, }; -use serde_json::{from_value, to_value}; use url::Url; impl CreateOrUpdateNote { @@ -99,8 +98,7 @@ impl CreateOrUpdateNote { inboxes.add_inbox(person.shared_inbox_or_inbox()); } - let activity = - AnnouncableActivities::CreateOrUpdateNoteWrapper(from_value(to_value(create_or_update)?)?); + let activity = AnnouncableActivities::CreateOrUpdateComment(create_or_update); send_activity_in_community(activity, &person, &community, inboxes, false, &context).await } } diff --git a/crates/apub/src/activities/create_or_update/mod.rs b/crates/apub/src/activities/create_or_update/mod.rs index b442e5fa3..c69e00e91 100644 --- a/crates/apub/src/activities/create_or_update/mod.rs +++ b/crates/apub/src/activities/create_or_update/mod.rs @@ -1,4 +1,3 @@ pub mod comment; -pub(crate) mod note_wrapper; pub mod post; pub mod private_message; diff --git a/crates/apub/src/activities/create_or_update/note_wrapper.rs b/crates/apub/src/activities/create_or_update/note_wrapper.rs deleted file mode 100644 index 9206d0c05..000000000 --- a/crates/apub/src/activities/create_or_update/note_wrapper.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::{ - objects::{community::ApubCommunity, note_wrapper::is_public}, - protocol::{ - activities::create_or_update::{ - note::CreateOrUpdateNote, - note_wrapper::CreateOrUpdateNoteWrapper, - private_message::CreateOrUpdatePrivateMessage, - }, - InCommunity, - }, -}; -use activitypub_federation::{config::Data, traits::ActivityHandler}; -use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{FederationError, LemmyError, LemmyResult}; -use serde_json::{from_value, to_value}; -use url::Url; - -#[async_trait::async_trait] -impl ActivityHandler for CreateOrUpdateNoteWrapper { - 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, context: &Data) -> LemmyResult<()> { - let val = to_value(self)?; - if is_public(&self.to, &self.cc) { - CreateOrUpdateNote::verify(&from_value(val)?, context).await?; - } else { - CreateOrUpdatePrivateMessage::verify(&from_value(val)?, context).await?; - } - Ok(()) - } - - #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> LemmyResult<()> { - let is_public = is_public(&self.to, &self.cc); - let val = to_value(self)?; - if is_public { - CreateOrUpdateNote::receive(from_value(val)?, context).await?; - } else { - CreateOrUpdatePrivateMessage::receive(from_value(val)?, context).await?; - } - Ok(()) - } -} - -#[async_trait::async_trait] -impl InCommunity for CreateOrUpdateNoteWrapper { - #[tracing::instrument(skip(self, context))] - async fn community(&self, context: &Data) -> LemmyResult { - if is_public(&self.to, &self.cc) { - let comment: CreateOrUpdateNote = from_value(to_value(self)?)?; - comment.community(context).await - } else { - Err(FederationError::ObjectIsNotPublic.into()) - } - } -} diff --git a/crates/apub/src/activities/create_or_update/private_message.rs b/crates/apub/src/activities/create_or_update/private_message.rs index b6e7478ef..6bba4e374 100644 --- a/crates/apub/src/activities/create_or_update/private_message.rs +++ b/crates/apub/src/activities/create_or_update/private_message.rs @@ -3,7 +3,7 @@ use crate::{ insert_received_activity, objects::{person::ApubPerson, private_message::ApubPrivateMessage}, protocol::activities::{ - create_or_update::private_message::CreateOrUpdatePrivateMessage, + create_or_update::chat_message::CreateOrUpdateChatMessage, CreateOrUpdateType, }, }; @@ -30,7 +30,7 @@ pub(crate) async fn send_create_or_update_pm( kind.clone(), &context.settings().get_protocol_and_hostname(), )?; - let create_or_update = CreateOrUpdatePrivateMessage { + let create_or_update = CreateOrUpdateChatMessage { id: id.clone(), actor: actor.id().into(), to: [recipient.id().into()], @@ -44,7 +44,7 @@ pub(crate) async fn send_create_or_update_pm( } #[async_trait::async_trait] -impl ActivityHandler for CreateOrUpdatePrivateMessage { +impl ActivityHandler for CreateOrUpdateChatMessage { type DataType = LemmyContext; type Error = LemmyError; diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index 941ac4237..15118a476 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -36,7 +36,7 @@ use lemmy_db_schema::{ community::{Community, CommunityUpdateForm}, person::Person, post::{Post, PostUpdateForm}, - private_message::{PrivateMessage as DbPrivateMessage, PrivateMessageUpdateForm}, + private_message::{PrivateMessage, PrivateMessageUpdateForm}, }, traits::Crud, }; @@ -82,7 +82,7 @@ pub(crate) async fn send_apub_delete_in_community( #[tracing::instrument(skip_all)] pub(crate) async fn send_apub_delete_private_message( actor: &ApubPerson, - pm: DbPrivateMessage, + pm: PrivateMessage, deleted: bool, context: Data, ) -> LemmyResult<()> { @@ -298,7 +298,7 @@ async fn receive_delete_action( } } DeletableObjects::PrivateMessage(pm) => { - DbPrivateMessage::update( + PrivateMessage::update( &mut context.pool(), pm.id, &PrivateMessageUpdateForm { diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index 0a11e30a0..7ed1d8baf 100644 --- a/crates/apub/src/activity_lists.rs +++ b/crates/apub/src/activity_lists.rs @@ -11,7 +11,11 @@ use crate::{ report::Report, update::UpdateCommunity, }, - create_or_update::{note_wrapper::CreateOrUpdateNoteWrapper, page::CreateOrUpdatePage}, + create_or_update::{ + chat_message::CreateOrUpdateChatMessage, + note::CreateOrUpdateNote, + page::CreateOrUpdatePage, + }, deletion::{delete::Delete, undo_delete::UndoDelete}, following::{ accept::AcceptFollow, @@ -44,17 +48,47 @@ pub enum SharedInboxActivities { AcceptFollow(AcceptFollow), RejectFollow(RejectFollow), UndoFollow(UndoFollow), + CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage), Report(Report), AnnounceActivity(AnnounceActivity), /// This is a catch-all and needs to be last RawAnnouncableActivities(RawAnnouncableActivities), } +/// List of activities which the group inbox can handle. +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +#[enum_delegate::implement(ActivityHandler)] +pub enum GroupInboxActivities { + Follow(Follow), + UndoFollow(UndoFollow), + Report(Report), + /// This is a catch-all and needs to be last + AnnouncableActivities(RawAnnouncableActivities), +} + +/// List of activities which the person inbox can handle. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(untagged)] +#[enum_delegate::implement(ActivityHandler)] +pub enum PersonInboxActivities { + Follow(Follow), + AcceptFollow(AcceptFollow), + RejectFollow(RejectFollow), + UndoFollow(UndoFollow), + CreateOrUpdatePrivateMessage(CreateOrUpdateChatMessage), + Delete(Delete), + UndoDelete(UndoDelete), + AnnounceActivity(AnnounceActivity), + /// User can also receive some "announcable" activities, eg a comment mention. + AnnouncableActivities(AnnouncableActivities), +} + #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(untagged)] #[enum_delegate::implement(ActivityHandler)] pub enum AnnouncableActivities { - CreateOrUpdateNoteWrapper(CreateOrUpdateNoteWrapper), + CreateOrUpdateComment(CreateOrUpdateNote), CreateOrUpdatePost(CreateOrUpdatePage), Vote(Vote), UndoVote(UndoVote), @@ -77,7 +111,7 @@ impl InCommunity for AnnouncableActivities { async fn community(&self, context: &Data) -> LemmyResult { use AnnouncableActivities::*; match self { - CreateOrUpdateNoteWrapper(a) => a.community(context).await, + CreateOrUpdateComment(a) => a.community(context).await, CreateOrUpdatePost(a) => a.community(context).await, Vote(a) => a.community(context).await, UndoVote(a) => a.community(context).await, @@ -99,32 +133,40 @@ impl InCommunity for AnnouncableActivities { mod tests { use crate::{ - activity_lists::SharedInboxActivities, + activity_lists::{GroupInboxActivities, PersonInboxActivities, SharedInboxActivities}, protocol::tests::{test_json, test_parse_lemmy_item}, }; use lemmy_utils::error::LemmyResult; + #[test] + fn test_group_inbox() -> LemmyResult<()> { + test_parse_lemmy_item::("assets/lemmy/activities/following/follow.json")?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_note.json", + )?; + Ok(()) + } + + #[test] + fn test_person_inbox() -> LemmyResult<()> { + test_parse_lemmy_item::( + "assets/lemmy/activities/following/accept.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_note.json", + )?; + test_parse_lemmy_item::( + "assets/lemmy/activities/create_or_update/create_private_message.json", + )?; + test_json::("assets/mastodon/activities/follow.json")?; + Ok(()) + } + #[test] fn test_shared_inbox() -> LemmyResult<()> { test_parse_lemmy_item::( "assets/lemmy/activities/deletion/delete_user.json", )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/following/accept.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_comment.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_private_message.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/following/follow.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_comment.json", - )?; - test_json::("assets/mastodon/activities/follow.json")?; Ok(()) } } diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 2c8ed9f9d..dc0721404 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -266,7 +266,7 @@ pub(crate) mod tests { let url = Url::parse("https://enterprise.lemmy.ml/comment/38741")?; let data = prepare_comment_test(&url, &context).await?; - let json: Note = file_to_json_object("assets/lemmy/objects/comment.json")?; + let json: Note = file_to_json_object("assets/lemmy/objects/note.json")?; ApubComment::verify(&json, &url, &context).await?; let comment = ApubComment::from_json(json.clone(), &context).await?; diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index 58841b29e..f837f7ad3 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -15,7 +15,6 @@ use std::fmt::Debug; pub mod comment; pub mod community; pub mod instance; -pub mod note_wrapper; pub mod person; pub mod post; pub mod private_message; diff --git a/crates/apub/src/objects/note_wrapper.rs b/crates/apub/src/objects/note_wrapper.rs deleted file mode 100644 index 5d613c7ae..000000000 --- a/crates/apub/src/objects/note_wrapper.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::comment::ApubComment; -use crate::{ - objects::private_message::ApubPrivateMessage, - protocol::objects::note_wrapper::NoteWrapper, -}; -use activitypub_federation::{config::Data, kinds::public, traits::Object}; -use chrono::{DateTime, Utc}; -use lemmy_api_common::{context::LemmyContext, LemmyErrorType}; -use lemmy_utils::error::{LemmyError, LemmyResult}; -use serde_json::{from_value, to_value}; -use url::Url; - -/// Private messages and public comments are quite awkward in Activitypub, because the json -/// format looks identical. They only way to differentiate them is to check for the presence -/// or absence of `https://www.w3.org/ns/activitystreams#Public` in `to` or `cc` which this -/// wrapper does. -#[derive(Debug)] -pub(crate) struct ApubNote {} - -#[async_trait::async_trait] -impl Object for ApubNote { - type DataType = LemmyContext; - type Kind = NoteWrapper; - type Error = LemmyError; - - fn last_refreshed_at(&self) -> Option> { - None - } - - #[tracing::instrument(skip_all)] - async fn read_from_id( - _object_id: Url, - _context: &Data, - ) -> LemmyResult> { - Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) - } - - #[tracing::instrument(skip_all)] - async fn delete(self, _context: &Data) -> LemmyResult<()> { - Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) - } - - async fn verify( - note: &NoteWrapper, - expected_domain: &Url, - context: &Data, - ) -> LemmyResult<()> { - let val = to_value(note)?; - if is_public(¬e.to, ¬e.cc) { - ApubComment::verify(&from_value(val)?, expected_domain, context).await?; - } else { - ApubPrivateMessage::verify(&from_value(val)?, expected_domain, context).await?; - } - Ok(()) - } - - async fn from_json(note: NoteWrapper, context: &Data) -> LemmyResult { - let is_public = is_public(¬e.to, ¬e.cc); - let val = to_value(note)?; - if is_public { - ApubComment::from_json(from_value(val)?, context).await?; - } else { - ApubPrivateMessage::from_json(from_value(val)?, context).await?; - } - Ok(ApubNote {}) - } - - async fn into_json(self, _context: &Data) -> LemmyResult { - Err(LemmyErrorType::Unknown("not implemented".to_string()).into()) - } -} - -pub(crate) fn is_public(to: &Option>, cc: &Option>) -> bool { - if let Some(to) = to { - if to.contains(&public()) { - return true; - } - } - if let Some(cc) = cc { - if cc.contains(&public()) { - return true; - } - } - false -} diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index ba64bd593..9ada5f657 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -4,7 +4,7 @@ use crate::{ fetcher::markdown_links::markdown_rewrite_remote_links, objects::read_from_string_or_source, protocol::{ - objects::private_message::{PrivateMessage, PrivateMessageType}, + objects::chat_message::{ChatMessage, ChatMessageType}, Source, }, }; @@ -25,11 +25,10 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ source::{ - instance::Instance, local_site::LocalSite, person::Person, person_block::PersonBlock, - private_message::{PrivateMessage as DbPrivateMessage, PrivateMessageInsertForm}, + private_message::{PrivateMessage, PrivateMessageInsertForm}, }, traits::Crud, }; @@ -38,22 +37,21 @@ use lemmy_utils::{ error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::markdown_to_html, }; -use semver::{Version, VersionReq}; use std::ops::Deref; use url::Url; #[derive(Clone, Debug)] -pub struct ApubPrivateMessage(pub(crate) DbPrivateMessage); +pub struct ApubPrivateMessage(pub(crate) PrivateMessage); impl Deref for ApubPrivateMessage { - type Target = DbPrivateMessage; + type Target = PrivateMessage; fn deref(&self) -> &Self::Target { &self.0 } } -impl From for ApubPrivateMessage { - fn from(pm: DbPrivateMessage) -> Self { +impl From for ApubPrivateMessage { + fn from(pm: PrivateMessage) -> Self { ApubPrivateMessage(pm) } } @@ -61,7 +59,7 @@ impl From for ApubPrivateMessage { #[async_trait::async_trait] impl Object for ApubPrivateMessage { type DataType = LemmyContext; - type Kind = PrivateMessage; + type Kind = ChatMessage; type Error = LemmyError; fn last_refreshed_at(&self) -> Option> { @@ -74,7 +72,7 @@ impl Object for ApubPrivateMessage { context: &Data, ) -> LemmyResult> { Ok( - DbPrivateMessage::read_from_apub_id(&mut context.pool(), object_id) + PrivateMessage::read_from_apub_id(&mut context.pool(), object_id) .await? .map(Into::into), ) @@ -86,26 +84,15 @@ impl Object for ApubPrivateMessage { } #[tracing::instrument(skip_all)] - async fn into_json(self, context: &Data) -> LemmyResult { + async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; let creator = Person::read(&mut context.pool(), creator_id).await?; let recipient_id = self.recipient_id; let recipient = Person::read(&mut context.pool(), recipient_id).await?; - let instance = Instance::read(&mut context.pool(), recipient.instance_id).await?; - let mut kind = PrivateMessageType::Note; - - // Deprecated: For Lemmy versions before 0.20, send private messages with old type - if let (Some(software), Some(version)) = (instance.software, &instance.version) { - let req = VersionReq::parse("<0.20")?; - if software == "lemmy" && req.matches(&Version::parse(version)?) { - kind = PrivateMessageType::ChatMessage - } - } - - let note = PrivateMessage { - kind, + let note = ChatMessage { + r#type: ChatMessageType::ChatMessage, id: self.ap_id.clone().into(), attributed_to: creator.actor_id.into(), to: [recipient.actor_id.into()], @@ -120,7 +107,7 @@ impl Object for ApubPrivateMessage { #[tracing::instrument(skip_all)] async fn verify( - note: &PrivateMessage, + note: &ChatMessage, expected_domain: &Url, context: &Data, ) -> LemmyResult<()> { @@ -141,7 +128,7 @@ impl Object for ApubPrivateMessage { #[tracing::instrument(skip_all)] async fn from_json( - note: PrivateMessage, + note: ChatMessage, context: &Data, ) -> LemmyResult { let creator = note.attributed_to.dereference(context).await?; @@ -174,7 +161,7 @@ impl Object for ApubPrivateMessage { local: Some(false), }; let timestamp = note.updated.or(note.published).unwrap_or_else(Utc::now); - let pm = DbPrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?; + let pm = PrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?; Ok(pm.into()) } } @@ -226,7 +213,7 @@ mod tests { let context = LemmyContext::init_test_context().await; let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?; let data = prepare_comment_test(&url, &context).await?; - let json: PrivateMessage = file_to_json_object("assets/lemmy/objects/private_message.json")?; + let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json")?; ApubPrivateMessage::verify(&json, &url, &context).await?; let pm = ApubPrivateMessage::from_json(json.clone(), &context).await?; @@ -238,7 +225,27 @@ mod tests { let to_apub = pm.into_json(&context).await?; assert_json_include!(actual: json, expected: to_apub); - DbPrivateMessage::delete(&mut context.pool(), pm_id).await?; + PrivateMessage::delete(&mut context.pool(), pm_id).await?; + cleanup(data, &context).await?; + Ok(()) + } + + #[tokio::test] + #[serial] + async fn test_parse_pleroma_pm() -> LemmyResult<()> { + let context = LemmyContext::init_test_context().await; + let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?; + let data = prepare_comment_test(&url, &context).await?; + let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2")?; + let json = file_to_json_object("assets/pleroma/objects/chat_message.json")?; + ApubPrivateMessage::verify(&json, &pleroma_url, &context).await?; + let pm = ApubPrivateMessage::from_json(json, &context).await?; + + assert_eq!(pm.ap_id, pleroma_url.into()); + assert_eq!(pm.content.len(), 3); + assert_eq!(context.request_count(), 0); + + PrivateMessage::delete(&mut context.pool(), pm.id).await?; cleanup(data, &context).await?; Ok(()) } diff --git a/crates/apub/src/protocol/activities/create_or_update/private_message.rs b/crates/apub/src/protocol/activities/create_or_update/chat_message.rs similarity index 75% rename from crates/apub/src/protocol/activities/create_or_update/private_message.rs rename to crates/apub/src/protocol/activities/create_or_update/chat_message.rs index 0c08f3991..30e94a28d 100644 --- a/crates/apub/src/protocol/activities/create_or_update/private_message.rs +++ b/crates/apub/src/protocol/activities/create_or_update/chat_message.rs @@ -1,6 +1,6 @@ use crate::{ objects::person::ApubPerson, - protocol::{activities::CreateOrUpdateType, objects::private_message::PrivateMessage}, + protocol::{activities::CreateOrUpdateType, objects::chat_message::ChatMessage}, }; use activitypub_federation::{fetch::object_id::ObjectId, protocol::helpers::deserialize_one}; use serde::{Deserialize, Serialize}; @@ -8,12 +8,12 @@ use url::Url; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct CreateOrUpdatePrivateMessage { +pub struct CreateOrUpdateChatMessage { pub(crate) id: Url, pub(crate) actor: ObjectId, #[serde(deserialize_with = "deserialize_one")] pub(crate) to: [ObjectId; 1], - pub(crate) object: PrivateMessage, + pub(crate) object: ChatMessage, #[serde(rename = "type")] pub(crate) kind: CreateOrUpdateType, } diff --git a/crates/apub/src/protocol/activities/create_or_update/mod.rs b/crates/apub/src/protocol/activities/create_or_update/mod.rs index d34be93c8..3d9dbbb1d 100644 --- a/crates/apub/src/protocol/activities/create_or_update/mod.rs +++ b/crates/apub/src/protocol/activities/create_or_update/mod.rs @@ -1,16 +1,14 @@ +pub mod chat_message; pub mod note; -pub(crate) mod note_wrapper; pub mod page; -pub mod private_message; #[cfg(test)] mod tests { - use super::note_wrapper::CreateOrUpdateNoteWrapper; use crate::protocol::{ activities::create_or_update::{ + chat_message::CreateOrUpdateChatMessage, note::CreateOrUpdateNote, page::CreateOrUpdatePage, - private_message::CreateOrUpdatePrivateMessage, }, tests::test_parse_lemmy_item, }; @@ -25,15 +23,9 @@ mod tests { "assets/lemmy/activities/create_or_update/update_page.json", )?; test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_comment.json", + "assets/lemmy/activities/create_or_update/create_note.json", )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_private_message.json", - )?; - test_parse_lemmy_item::( - "assets/lemmy/activities/create_or_update/create_comment.json", - )?; - test_parse_lemmy_item::( + test_parse_lemmy_item::( "assets/lemmy/activities/create_or_update/create_private_message.json", )?; Ok(()) diff --git a/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs b/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs deleted file mode 100644 index bc53c80fd..000000000 --- a/crates/apub/src/protocol/activities/create_or_update/note_wrapper.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::protocol::objects::note_wrapper::NoteWrapper; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; -use url::Url; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateOrUpdateNoteWrapper { - object: NoteWrapper, - pub(crate) id: Url, - pub(crate) actor: Url, - pub(crate) to: Option>, - pub(crate) cc: Option>, - #[serde(flatten)] - other: Map, -} diff --git a/crates/apub/src/protocol/mod.rs b/crates/apub/src/protocol/mod.rs index 9f218e351..a4774ac1d 100644 --- a/crates/apub/src/protocol/mod.rs +++ b/crates/apub/src/protocol/mod.rs @@ -116,7 +116,6 @@ pub(crate) mod tests { // parse file into hashmap, which ensures that every field is included let raw = file_to_json_object::>(path)?; // assert that all fields are identical, otherwise print diff - //dbg!(&parsed, &raw); assert_json_include!(actual: &parsed, expected: raw); Ok(parsed) } diff --git a/crates/apub/src/protocol/objects/private_message.rs b/crates/apub/src/protocol/objects/chat_message.rs similarity index 79% rename from crates/apub/src/protocol/objects/private_message.rs rename to crates/apub/src/protocol/objects/chat_message.rs index bf7fe90cb..8cb83e664 100644 --- a/crates/apub/src/protocol/objects/private_message.rs +++ b/crates/apub/src/protocol/objects/chat_message.rs @@ -16,9 +16,8 @@ use serde_with::skip_serializing_none; #[skip_serializing_none] #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct PrivateMessage { - #[serde(rename = "type")] - pub(crate) kind: PrivateMessageType, +pub struct ChatMessage { + pub(crate) r#type: ChatMessageType, pub(crate) id: ObjectId, pub(crate) attributed_to: ObjectId, #[serde(deserialize_with = "deserialize_one")] @@ -32,10 +31,8 @@ pub struct PrivateMessage { pub(crate) updated: Option>, } +/// https://docs.pleroma.social/backend/development/ap_extensions/#chatmessages #[derive(Clone, Debug, Deserialize, Serialize)] -pub enum PrivateMessageType { - /// For compatibility with Lemmy 0.19 and earlier - /// https://docs.pleroma.social/backend/development/ap_extensions/#chatmessages +pub enum ChatMessageType { ChatMessage, - Note, } diff --git a/crates/apub/src/protocol/objects/mod.rs b/crates/apub/src/protocol/objects/mod.rs index 757f49ae4..00fe26d2b 100644 --- a/crates/apub/src/protocol/objects/mod.rs +++ b/crates/apub/src/protocol/objects/mod.rs @@ -8,13 +8,12 @@ use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; +pub(crate) mod chat_message; pub(crate) mod group; pub(crate) mod instance; pub(crate) mod note; -pub(crate) mod note_wrapper; pub(crate) mod page; pub(crate) mod person; -pub(crate) mod private_message; pub(crate) mod tombstone; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] @@ -102,15 +101,14 @@ impl LanguageTag { #[cfg(test)] mod tests { - use super::note_wrapper::NoteWrapper; use crate::protocol::{ objects::{ + chat_message::ChatMessage, group::Group, instance::Instance, note::Note, page::Page, person::Person, - private_message::PrivateMessage, tombstone::Tombstone, }, tests::{test_json, test_parse_lemmy_item}, @@ -123,10 +121,8 @@ mod tests { test_parse_lemmy_item::("assets/lemmy/objects/group.json")?; test_parse_lemmy_item::("assets/lemmy/objects/person.json")?; test_parse_lemmy_item::("assets/lemmy/objects/page.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/comment.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/private_message.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/comment.json")?; - test_parse_lemmy_item::("assets/lemmy/objects/private_message.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/note.json")?; + test_parse_lemmy_item::("assets/lemmy/objects/chat_message.json")?; test_parse_lemmy_item::("assets/lemmy/objects/tombstone.json")?; Ok(()) } @@ -135,6 +131,7 @@ mod tests { fn test_parse_objects_pleroma() -> LemmyResult<()> { test_json::("assets/pleroma/objects/person.json")?; test_json::("assets/pleroma/objects/note.json")?; + test_json::("assets/pleroma/objects/chat_message.json")?; Ok(()) } diff --git a/crates/apub/src/protocol/objects/note_wrapper.rs b/crates/apub/src/protocol/objects/note_wrapper.rs deleted file mode 100644 index f1bcf605b..000000000 --- a/crates/apub/src/protocol/objects/note_wrapper.rs +++ /dev/null @@ -1,14 +0,0 @@ -use activitypub_federation::kinds::object::NoteType; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; -use url::Url; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct NoteWrapper { - pub(crate) r#type: NoteType, - pub(crate) to: Option>, - pub(crate) cc: Option>, - #[serde(flatten)] - other: Map, -}