From beec08027495c43cc5f016ba38f5d4a2942c3ee9 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Mon, 29 Apr 2024 12:34:11 +0200 Subject: [PATCH] Testing for federation with NodeBB, make community.followers_url optional (#4629) * Testing for federation with NodeBB, make community.followers_url optional * clippy --- crates/apub/assets/nodebb/objects/group.json | 22 +++++++++++ crates/apub/assets/nodebb/objects/page.json | 38 +++++++++++++++++++ crates/apub/assets/nodebb/objects/person.json | 29 ++++++++++++++ .../apub/src/activities/community/announce.rs | 7 +++- .../apub/src/activities/community/update.rs | 2 +- crates/apub/src/objects/community.rs | 16 ++++---- crates/apub/src/protocol/objects/group.rs | 2 +- crates/apub/src/protocol/objects/mod.rs | 8 ++++ crates/db_schema/src/schema.rs | 2 +- crates/db_schema/src/source/community.rs | 4 +- .../down.sql | 3 ++ .../up.sql | 3 ++ 12 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 crates/apub/assets/nodebb/objects/group.json create mode 100644 crates/apub/assets/nodebb/objects/page.json create mode 100644 crates/apub/assets/nodebb/objects/person.json create mode 100644 migrations/2024-04-15-105932_community_followers_url_optional/down.sql create mode 100644 migrations/2024-04-15-105932_community_followers_url_optional/up.sql diff --git a/crates/apub/assets/nodebb/objects/group.json b/crates/apub/assets/nodebb/objects/group.json new file mode 100644 index 0000000000..462300ce9b --- /dev/null +++ b/crates/apub/assets/nodebb/objects/group.json @@ -0,0 +1,22 @@ +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://community.nodebb.org/category/31", + "url": "https://community.nodebb.org/category/31/threadiverse-working-group", + "inbox": "https://community.nodebb.org/category/31/inbox", + "outbox": "https://community.nodebb.org/category/31/outbox", + "sharedInbox": "https://community.nodebb.org/inbox", + "type": "Group", + "name": "Threadiverse Working Group", + "preferredUsername": "swicg-threadiverse-wg", + "summary": "Discussion and announcements related to the SWICG Threadiverse task force", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://community.nodebb.org/assets/uploads/system/site-logo.png" + }, + "publicKey": { + "id": "https://community.nodebb.org/category/31#key", + "owner": "https://community.nodebb.org/category/31", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0/Or3Ox2/jbhBZzF8W0Y\nWuS/4lgm5O5rxQk2nDRBXU/qNaZnMPkW2FxFPuPetndUVKSD2+vWF3SUlFyZ/vhT\nITzLkbRSILMiZCUg+0mvqi6va1WMBglMe5jLkc7wdfgNsosqBzKMdyMxqDZr++mJ\n8DjuqzWHENcjWcbMfSfAa9nkZHBIQUsHGGIwxEbKNlPqF0JIB66py7xmXbboDxpD\nPVF3EMkgZNnbmDGtlkZCKbztradyNRVl/u6KJpV3fbi+m/8CZ+POc4I5sKCQY1Hr\ndslHlm6tCkJQxIIKQtz0ZJ5yCUYmk48C2gFCndfJtYoEy9iR62xSemky6y04gWVc\naQIDAQAB\n-----END PUBLIC KEY-----\n" + } +} diff --git a/crates/apub/assets/nodebb/objects/page.json b/crates/apub/assets/nodebb/objects/page.json new file mode 100644 index 0000000000..794ea17146 --- /dev/null +++ b/crates/apub/assets/nodebb/objects/page.json @@ -0,0 +1,38 @@ +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://community.nodebb.org/topic/17908", + "type": "Page", + "to": ["https://www.w3.org/ns/activitystreams#Public"], + "cc": ["https://community.nodebb.org/uid/2/followers"], + "inReplyTo": null, + "published": "2024-03-19T20:25:39.462Z", + "url": "https://community.nodebb.org/topic/17908/threadiverse-working-group", + "attributedTo": "https://community.nodebb.org/uid/2", + "audience": "https://community.nodebb.org/category/31/threadiverse-working-group", + "sensitive": false, + "summary": null, + "name": "Threadiverse Working Group", + "content": "

NodeBB is at this year's FediForum, and one of the breakout sessions centred around the Theadiverse, the subset of ActivityPub-enabled applications built around a topic-centric model of content representation.

\n

Some of the topic touched upon included:

\n\n

The main action item involved the genesis of an informal working group for the threadiverse, in order to align our disparate implementations toward a common path.

\n

We intend to meet monthly at first, with the first meeting likely sometime early-to-mid April.

\n

The topic of the first WG call is: Representation of the higherlevel collection of Notes (posts, etc.) — Article vs. Page, etc?

\n

Interested?

\n\n
\n

As an aside, I'd love to try something new and attempt tokeep as much of this as I can on the social web. Can you do me a favour and boost this to your followers?

\n", + "source": { + "content": "NodeBB is at this year's FediForum, and one of the breakout sessions centred around **the Theadiverse**, the subset of ActivityPub-enabled applications built around a topic-centric model of content representation.\n\nSome of the topic touched upon included:\n\n* Aligning on a standard representation for collections of Notes\n* FEP-1b12 — Group federation and implementation thereof by Lemmy, et al.\n* Offering a comparatively more feature-rich experience vis-a-vis restrictions re: microblogging\n* Going forward: collaborating on building compatible threadiverse implementations\n\nThe main action item involved **the genesis of an informal working group for the threadiverse**, in order to align our disparate implementations toward a common path.\n\nWe intend to meet monthly at first, with the first meeting likely sometime early-to-mid April.\n\nThe topic of the first WG call is: **Representation of the higher level collection of Notes (posts, etc.) — Article vs. Page, etc?**\n\nInterested?\n\n* Publicly reply to this post (NodeBB does not support non-public postsat this time) if you'd like to join the list\n* If you prefer to remain private, please email julian@nodebb.org\n\n----\n\nAs an aside, I'd love to try something new and attempt to keep as much of this as I can on the social web. Can you do me a favour and boost this to your followers?", + "mediaType": "text/markdown" + }, + "tag": [ + { + "type": "Hashtag", + "href": "https://community.nodebb.org/tags/fediforum", + "name": "#fediforum" + }, + { + "type": "Hashtag", + "href": "https://community.nodebb.org/tags/activitypub", + "name": "#activitypub" + }, + { + "type": "Hashtag", + "href": "https://community.nodebb.org/tags/threadiverse", + "name": "#threadiverse" + } + ], + "attachment": [] +} diff --git a/crates/apub/assets/nodebb/objects/person.json b/crates/apub/assets/nodebb/objects/person.json new file mode 100644 index 0000000000..aa2ee5c8c9 --- /dev/null +++ b/crates/apub/assets/nodebb/objects/person.json @@ -0,0 +1,29 @@ +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://community.nodebb.org/uid/2", + "url": "https://community.nodebb.org/user/julian", + "followers": "https://community.nodebb.org/uid/2/followers", + "following": "https://community.nodebb.org/uid/2/following", + "inbox": "https://community.nodebb.org/uid/2/inbox", + "outbox": "https://community.nodebb.org/uid/2/outbox", + "sharedInbox": "https://community.nodebb.org/inbox", + "type": "Person", + "name": "julian", + "preferredUsername": "julian", + "summary": "Hi! I'm Julian, one of the co-founders of NodeBB, the forum software you are using right now.\r\n\r\nI started this company with two colleagues, Baris and Andrew, in 2013, and have been doing the startup thing since (although I think at some point along the way we stopped being a startup and just became a boring ol' small business).\r\n\r\nIn my free time I rock climb, cycle, and lift weights. I live just outside Toronto, Canada, with my wife and three children.", + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://community.nodebb.org/assets/uploads/profile/uid-2/2-profileavatar-1701457270279.jpeg" + }, + "image": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://community.nodebb.org/assets/uploads/profile/uid-2/2-profilecover-1649468285913.jpeg" + }, + "publicKey": { + "id": "https://community.nodebb.org/uid/2#key", + "owner": "https://community.nodebb.org/uid/2", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzEr0sFdATahQzprS4EOT\nZq+KMc6UTbt2GDP20OrQi/P5AXAbMaQiRCRdGWhYGjnH0jicn5NnozNxRo+HchJT\nV6NOHxpsxqPCoaLeoBkhfhbSCLr2Gzil6mmfqf9TjnI7A7ZTtCc0G+n0ztyL9HwL\nkEAI178l2gckk4XKKYnEd+dyiIevExrq/ROLgwW1o428FZvlF5amKxhpVUEygRU8\nCd1hqWYs+xYDOJURCP5qEx/MmRPpV/yGMTMyF+/gcQc0TUZnhWAM2E4M+aq3aKh6\nJP/vsry+5YZPUaPWfopbT5Ijyt6ZSElp6Avkg56eTz0a5SRcjCVS6IFVPwiLlzOe\nYwIDAQAB\n-----END PUBLIC KEY-----\n" + } +} diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 9a39288829..aebf282175 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -94,7 +94,12 @@ impl AnnounceActivity { actor: community.id().into(), to: vec![public()], object: IdOrNestedObject::NestedObject(object), - cc: vec![community.followers_url.clone().into()], + cc: community + .followers_url + .clone() + .map(Into::into) + .into_iter() + .collect(), kind: AnnounceType::Announce, id, }) diff --git a/crates/apub/src/activities/community/update.rs b/crates/apub/src/activities/community/update.rs index 3457e6c248..f507b34257 100644 --- a/crates/apub/src/activities/community/update.rs +++ b/crates/apub/src/activities/community/update.rs @@ -105,7 +105,7 @@ impl ActivityHandler for UpdateCommunity { last_refreshed_at: Some(naive_now()), icon: Some(self.object.icon.map(|i| i.url.into())), banner: Some(self.object.image.map(|i| i.url.into())), - followers_url: Some(self.object.followers.into()), + followers_url: self.object.followers.map(Into::into), inbox_url: Some(self.object.inbox.into()), shared_inbox_url: Some(self.object.endpoints.map(|e| e.shared_inbox.into())), moderators_url: self.object.attributed_to.map(Into::into), diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 1526a1a370..4e719895a9 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -113,7 +113,7 @@ impl Object for ApubCommunity { featured: Some(generate_featured_url(&self.actor_id)?.into()), inbox: self.inbox_url.clone().into(), outbox: generate_outbox_url(&self.actor_id)?.into(), - followers: self.followers_url.clone().into(), + followers: self.followers_url.clone().map(Into::into), endpoints: self.shared_inbox_url.clone().map(|s| Endpoints { shared_inbox: s.into(), }), @@ -164,7 +164,7 @@ impl Object for ApubCommunity { last_refreshed_at: Some(naive_now()), icon, banner, - followers_url: Some(group.followers.clone().into()), + followers_url: group.followers.clone().map(Into::into), inbox_url: Some(group.inbox.into()), shared_inbox_url: group.endpoints.map(|e| e.shared_inbox.into()), moderators_url: group.attributed_to.clone().map(Into::into), @@ -187,11 +187,9 @@ impl Object for ApubCommunity { let context_ = context.reset_request_count(); spawn_try_task(async move { group.outbox.dereference(&community_, &context_).await.ok(); - group - .followers - .dereference(&community_, &context_) - .await - .ok(); + if let Some(followers) = group.followers { + followers.dereference(&community_, &context_).await.ok(); + } if let Some(featured) = group.featured { featured.dereference(&community_, &context_).await.ok(); } @@ -275,7 +273,9 @@ pub(crate) mod tests { // change these links so they dont fetch over the network json.attributed_to = None; json.outbox = CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox")?; - json.followers = CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_followers")?; + json.followers = Some(CollectionId::parse( + "https://enterprise.lemmy.ml/c/tenforward/not_followers", + )?); let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward")?; ApubCommunity::verify(&json, &url, &context2).await?; diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index 2ed8844842..a95fff262f 100644 --- a/crates/apub/src/protocol/objects/group.rs +++ b/crates/apub/src/protocol/objects/group.rs @@ -45,7 +45,7 @@ pub struct Group { /// username, set at account creation and usually fixed after that pub(crate) preferred_username: String, pub(crate) inbox: Url, - pub(crate) followers: CollectionId, + pub(crate) followers: Option>, pub(crate) public_key: PublicKey, /// title diff --git a/crates/apub/src/protocol/objects/mod.rs b/crates/apub/src/protocol/objects/mod.rs index efda3d7ed4..77d173f30e 100644 --- a/crates/apub/src/protocol/objects/mod.rs +++ b/crates/apub/src/protocol/objects/mod.rs @@ -190,4 +190,12 @@ mod tests { test_json::("assets/mobilizon/objects/person.json")?; Ok(()) } + + #[test] + fn test_parse_object_nodebb() -> LemmyResult<()> { + test_json::("assets/nodebb/objects/group.json")?; + test_json::("assets/nodebb/objects/page.json")?; + test_json::("assets/nodebb/objects/person.json")?; + Ok(()) + } } diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 408ed05403..50bdac751c 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -178,7 +178,7 @@ diesel::table! { icon -> Nullable, banner -> Nullable, #[max_length = 255] - followers_url -> Varchar, + followers_url -> Nullable, #[max_length = 255] inbox_url -> Varchar, #[max_length = 255] diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index 434fa70372..16a17819cd 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -49,8 +49,8 @@ pub struct Community { /// A URL for a banner. pub banner: Option, #[cfg_attr(feature = "full", ts(skip))] - #[serde(skip, default = "placeholder_apub_url")] - pub followers_url: DbUrl, + #[serde(skip)] + pub followers_url: Option, #[cfg_attr(feature = "full", ts(skip))] #[serde(skip, default = "placeholder_apub_url")] pub inbox_url: DbUrl, diff --git a/migrations/2024-04-15-105932_community_followers_url_optional/down.sql b/migrations/2024-04-15-105932_community_followers_url_optional/down.sql new file mode 100644 index 0000000000..68ad343778 --- /dev/null +++ b/migrations/2024-04-15-105932_community_followers_url_optional/down.sql @@ -0,0 +1,3 @@ +ALTER TABLE community + ALTER COLUMN followers_url SET NOT NULL; + diff --git a/migrations/2024-04-15-105932_community_followers_url_optional/up.sql b/migrations/2024-04-15-105932_community_followers_url_optional/up.sql new file mode 100644 index 0000000000..3b0ddaec1a --- /dev/null +++ b/migrations/2024-04-15-105932_community_followers_url_optional/up.sql @@ -0,0 +1,3 @@ +ALTER TABLE community + ALTER COLUMN followers_url DROP NOT NULL; +