diff --git a/crates/apub/assets/gnusocial/activities/create_note.json b/crates/apub/assets/gnusocial/activities/create_note.json
new file mode 100644
index 000000000..9e4221bb4
--- /dev/null
+++ b/crates/apub/assets/gnusocial/activities/create_note.json
@@ -0,0 +1,53 @@
+{
+ "type": "Create",
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://instance.gnusocial.test/activity/1339",
+ "published": "2022-03-01T20:58:48+00:00",
+ "actor": "https://instance.gnusocial.test/actor/42",
+ "object": {
+ "type": "Note",
+ "id": "https://instance.gnusocial.test/object/note/1339",
+ "published": "2022-03-01T21:00:16+00:00",
+ "attributedTo": "https://instance.gnusocial.test/actor/42",
+ "content": "
yay ^^
",
+ "mediaType": "text/html",
+ "source": {
+ "content": "yay ^^",
+ "mediaType": "text/plain"
+ },
+ "attachment": [],
+ "tag": [],
+ "inReplyTo": "https://instance.gnusocial.test/object/note/1338",
+ "inConversation": "https://instance.gnusocial.test/conversation/1338",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/42/subscribers"
+ ]
+ },
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/42/subscribers"
+ ]
+}
diff --git a/crates/apub/assets/gnusocial/activities/create_page.json b/crates/apub/assets/gnusocial/activities/create_page.json
new file mode 100644
index 000000000..2ce600cf7
--- /dev/null
+++ b/crates/apub/assets/gnusocial/activities/create_page.json
@@ -0,0 +1,53 @@
+{
+ "type": "Create",
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://instance.gnusocial.test/activity/1338",
+ "published": "2022-03-17T23:30:26+00:00",
+ "actor": "https://instance.gnusocial.test/actor/42",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/21"
+ ],
+ "object": {
+ "type": "Page",
+ "id": "https://instance.gnusocial.test/object/note/1338",
+ "published": "2022-03-17T23:30:26+00:00",
+ "attributedTo": "https://instance.gnusocial.test/actor/42",
+ "name": "hello, world.",
+ "content": "This is an interesting page.
",
+ "mediaType": "text/html",
+ "source": {
+ "content": "This is an interesting page.",
+ "mediaType": "text/markdown"
+ },
+ "attachment": [],
+ "tag": [],
+ "inConversation": "https://instance.gnusocial.test/conversation/1338",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/21"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/crates/apub/assets/gnusocial/activities/like_note.json b/crates/apub/assets/gnusocial/activities/like_note.json
new file mode 100644
index 000000000..09ce40ef5
--- /dev/null
+++ b/crates/apub/assets/gnusocial/activities/like_note.json
@@ -0,0 +1,16 @@
+{
+ "type": "Like",
+ "@context": [
+ "https://www.w3.org/ns/activitystreams"
+ ],
+ "id": "https://another_instance.gnusocial.test/activity/41362",
+ "published": "2022-03-20T17:54:15+00:00",
+ "actor": "https://another_instance.gnusocial.test/actor/43",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/42"
+ ],
+ "object": "https://instance.gnusocial.test/object/note/1337"
+}
diff --git a/crates/apub/assets/gnusocial/objects/group.json b/crates/apub/assets/gnusocial/objects/group.json
new file mode 100644
index 000000000..9be83c2de
--- /dev/null
+++ b/crates/apub/assets/gnusocial/objects/group.json
@@ -0,0 +1,42 @@
+{
+ "type": "Group",
+ "streams": [],
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://instance.gnusocial.test/actor/21",
+ "inbox": "https://instance.gnusocial.test/actor/21/inbox.json",
+ "outbox": "https://instance.gnusocial.test/actor/21/outbox.json",
+ "following": "https://instance.gnusocial.test/actor/21/subscriptions",
+ "followers": "https://instance.gnusocial.test/actor/21/subscribers",
+ "liked": "https://instance.gnusocial.test/actor/21/favourites",
+ "preferredUsername": "hackers",
+ "publicKey": {
+ "id": "https://instance.gnusocial.test/actor/2#public-key",
+ "owner": "https://instance.gnusocial.test/actor/2",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZyKL+GyJbTV/ilVBlzz\n8OL/UwNi3KpfV5kQwXU0pPcBbw6y2JOfWnKUT1CfiHG3ntiOFnc+wQfHZk4hRSE8\n9Xe/G5Y215xW+gqx/kjt2GOENqzSzYXdEZ5Qsx6yumZD/yb6VZK9Og0HjX2mpRs9\nbactY76w4BQVntjZ17gSkMhYcyPFZTAIe7QDkeSPk5lkXfTwtaB3YcJSbQ3+s7La\npeEgukQDkrLUIP6cxayKrgUl4fhHdpx1Yk4Bzd/1XkZCjeBca94lP1p2M12amI+Z\nOLSTuLyEiCcku8aN+Ms9plwATmIDaGvKFVk0YVtBHdIJlYXV0yIscab3bqyhsLBK\njwIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "name": "Hackers!",
+ "published": "2022-02-23T21:54:52+00:00",
+ "updated": "2022-02-23T21:55:16+00:00",
+ "url": "https://instance.gnusocial.test/!hackers",
+ "endpoints": {
+ "sharedInbox": "https://instance.gnusocial.test/inbox.json"
+ }
+}
diff --git a/crates/apub/assets/gnusocial/objects/note.json b/crates/apub/assets/gnusocial/objects/note.json
new file mode 100644
index 000000000..08f58a93b
--- /dev/null
+++ b/crates/apub/assets/gnusocial/objects/note.json
@@ -0,0 +1,44 @@
+{
+ "type": "Note",
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ },
+ {
+ "@language": "en"
+ }
+ ],
+ "id": "https://instance.gnusocial.test/object/note/1339",
+ "published": "2022-03-01T21:00:16+00:00",
+ "attributedTo": "https://instance.gnusocial.test/actor/42",
+ "content": "yay ^^
",
+ "mediaType": "text/html",
+ "source": {
+ "content": "yay ^^",
+ "mediaType": "text/plain"
+ },
+ "attachment": [],
+ "tag": [],
+ "inReplyTo": "https://instance.gnusocial.test/object/note/1338",
+ "inConversation": "https://instance.gnusocial.test/conversation/1338",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/42/subscribers"
+ ]
+}
diff --git a/crates/apub/assets/gnusocial/objects/page.json b/crates/apub/assets/gnusocial/objects/page.json
new file mode 100644
index 000000000..f66d28854
--- /dev/null
+++ b/crates/apub/assets/gnusocial/objects/page.json
@@ -0,0 +1,41 @@
+{
+ "type": "Page",
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://instance.gnusocial.test/object/note/1338",
+ "published": "2022-03-17T23:30:26+00:00",
+ "attributedTo": "https://instance.gnusocial.test/actor/42",
+ "name": "hello, world.",
+ "content": "This is an interesting page.
",
+ "mediaType": "text/html",
+ "source": {
+ "content": "This is an interesting page.",
+ "mediaType": "text/markdown"
+ },
+ "attachment": [],
+ "tag": [],
+ "inConversation": "https://instance.gnusocial.test/conversation/1338",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://instance.gnusocial.test/actor/21"
+ ]
+}
diff --git a/crates/apub/assets/gnusocial/objects/person.json b/crates/apub/assets/gnusocial/objects/person.json
new file mode 100644
index 000000000..c6338437b
--- /dev/null
+++ b/crates/apub/assets/gnusocial/objects/person.json
@@ -0,0 +1,42 @@
+{
+ "type": "Person",
+ "streams": [],
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "gs": "https://www.gnu.org/software/social/ns#"
+ },
+ {
+ "litepub": "http://litepub.social/ns#"
+ },
+ {
+ "chatMessage": "litepub:chatMessage"
+ },
+ {
+ "inConversation": {
+ "@id": "gs:inConversation",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://instance.gnusocial.test/actor/42",
+ "inbox": "https://instance.gnusocial.test/actor/42/inbox.json",
+ "outbox": "https://instance.gnusocial.test/actor/42/outbox.json",
+ "following": "https://instance.gnusocial.test/actor/42/subscriptions",
+ "followers": "https://instance.gnusocial.test/actor/42/subscribers",
+ "liked": "https://instance.gnusocial.test/actor/42/favourites",
+ "preferredUsername": "diogo",
+ "publicKey": {
+ "id": "https://instance.gnusocial.test/actor/42#public-key",
+ "owner": "https://instance.gnusocial.test/actor/42",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBB+3ldwA2qC1hQTtIho\n9KYhvvMlPdydn8dA6OlyIQ3Jy57ADt2e144jDSY5RQ3esmzWm2QqsI8rAsZsAraO\nl2+855y7Fw35WH4GBc7PJ6MLAEvMk1YWeS/rttXaDzh2i4n/AXkMuxDjS1IBqw2w\nn0qTz2sdGcBJ+mop6AB9Qt2lseBc5IW040jSnfLEDDIaYgoc5m2yRsjGKItOh3BG\njGHDb6JB9FySToSMGIt0/tE5k06wfvAxtkxX5dfGeKtciBpC2MGT169iyMIOM8DN\nFhSl8mowtV1NJQ7nN692USrmNvSJjqe9ugPCDPPvwQ5A6A61Qrgpz5pav/o5Sz69\nzQIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "name": "Diogo Peralta Cordeiro",
+ "published": "2022-02-23T17:20:30+00:00",
+ "updated": "2022-02-25T02:12:48+00:00",
+ "url": "https://instance.gnusocial.test/@diogo",
+ "endpoints": {
+ "sharedInbox": "https://instance.gnusocial.test/inbox.json"
+ }
+}
diff --git a/crates/apub/assets/lemmy/activities/voting/dislike_page.json b/crates/apub/assets/lemmy/activities/voting/dislike_page.json
index 822a9d357..6683a6663 100644
--- a/crates/apub/assets/lemmy/activities/voting/dislike_page.json
+++ b/crates/apub/assets/lemmy/activities/voting/dislike_page.json
@@ -1,11 +1,11 @@
{
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": "http://ds9.lemmy.ml/post/1",
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Dislike",
"id": "http://enterprise.lemmy.ml/activities/dislike/64d40d40-a829-43a5-8247-1fb595b3ca1c"
diff --git a/crates/apub/assets/lemmy/activities/voting/like_note.json b/crates/apub/assets/lemmy/activities/voting/like_note.json
index 35e969060..e9fc366ae 100644
--- a/crates/apub/assets/lemmy/activities/voting/like_note.json
+++ b/crates/apub/assets/lemmy/activities/voting/like_note.json
@@ -1,11 +1,11 @@
{
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": "http://ds9.lemmy.ml/comment/1",
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Like",
"id": "http://ds9.lemmy.ml/activities/like/fd61d070-7382-46a9-b2b7-6bb253732877"
diff --git a/crates/apub/assets/lemmy/activities/voting/undo_dislike_page.json b/crates/apub/assets/lemmy/activities/voting/undo_dislike_page.json
index 4123ebab4..2234e4104 100644
--- a/crates/apub/assets/lemmy/activities/voting/undo_dislike_page.json
+++ b/crates/apub/assets/lemmy/activities/voting/undo_dislike_page.json
@@ -1,22 +1,22 @@
{
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": {
"actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": "http://ds9.lemmy.ml/post/1",
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Like",
"id": "http://enterprise.lemmy.ml/activities/like/2227ab2c-79e2-4fca-a1d2-1d67dacf2457"
},
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Undo",
"id": "http://enterprise.lemmy.ml/activities/undo/6cc6fb71-39fe-49ea-9506-f0423b101e98"
diff --git a/crates/apub/assets/lemmy/activities/voting/undo_like_note.json b/crates/apub/assets/lemmy/activities/voting/undo_like_note.json
index 84a6efe50..e22c8fd1f 100644
--- a/crates/apub/assets/lemmy/activities/voting/undo_like_note.json
+++ b/crates/apub/assets/lemmy/activities/voting/undo_like_note.json
@@ -1,22 +1,22 @@
{
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": {
"actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
"to": [
- "https://www.w3.org/ns/activitystreams#Public"
+ "http://enterprise.lemmy.ml/c/main"
],
"object": "http://ds9.lemmy.ml/comment/1",
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Like",
"id": "http://ds9.lemmy.ml/activities/like/efcf7ae2-dfcc-4ff4-9ce4-6adf251ff004"
},
"cc": [
- "http://enterprise.lemmy.ml/c/main"
+ "https://www.w3.org/ns/activitystreams#Public"
],
"type": "Undo",
"id": "http://ds9.lemmy.ml/activities/undo/3518565c-24a7-4d9e-8e0a-f7a2f45ac618"
diff --git a/crates/apub/src/activities/voting/undo_vote.rs b/crates/apub/src/activities/voting/undo_vote.rs
index 3606756a3..16ea64e00 100644
--- a/crates/apub/src/activities/voting/undo_vote.rs
+++ b/crates/apub/src/activities/voting/undo_vote.rs
@@ -28,6 +28,9 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
impl UndoVote {
+ /// UndoVote has as:Public value in cc field, unlike other activities. This indicates to other
+ /// software (like GNU social, or presumably Mastodon), that the like actor should not be
+ /// disclosed.
#[tracing::instrument(skip_all)]
pub async fn send(
object: &PostOrComment,
@@ -49,9 +52,9 @@ impl UndoVote {
)?;
let undo_vote = UndoVote {
actor: ObjectId::new(actor.actor_id()),
- to: vec![public()],
+ to: vec![community.actor_id()],
object,
- cc: vec![community.actor_id()],
+ cc: vec![public()],
kind: UndoType::Undo,
id: id.clone(),
unparsed: Default::default(),
diff --git a/crates/apub/src/activities/voting/vote.rs b/crates/apub/src/activities/voting/vote.rs
index 11ed9b360..ce6dee28f 100644
--- a/crates/apub/src/activities/voting/vote.rs
+++ b/crates/apub/src/activities/voting/vote.rs
@@ -28,6 +28,8 @@ use lemmy_db_schema::{
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
+/// Vote has as:Public value in cc field, unlike other activities. This indicates to other software
+/// (like GNU social, or presumably Mastodon), that the like actor should not be disclosed.
impl Vote {
pub(in crate::activities::voting) fn new(
object: &PostOrComment,
@@ -38,9 +40,9 @@ impl Vote {
) -> Result {
Ok(Vote {
actor: ObjectId::new(actor.actor_id()),
- to: vec![public()],
+ to: vec![community.actor_id()],
object: ObjectId::new(object.ap_id()),
- cc: vec![community.actor_id()],
+ cc: vec![public()],
kind: kind.clone(),
id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
unparsed: Default::default(),
diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs
index 2b706aac5..bc8caceaa 100644
--- a/crates/apub/src/objects/comment.rs
+++ b/crates/apub/src/objects/comment.rs
@@ -2,18 +2,15 @@ use crate::{
activities::{verify_is_public, verify_person_in_community},
check_is_apub_id_valid,
mentions::collect_non_local_mentions,
+ objects::read_from_string_or_source,
protocol::{
- objects::{
- note::{Note, SourceCompat},
- tombstone::Tombstone,
- },
- Source,
+ objects::{note::Note, tombstone::Tombstone},
+ SourceCompat,
},
PostOrComment,
};
use activitystreams_kinds::{object::NoteType, public};
use chrono::NaiveDateTime;
-use html2md::parse_html;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
@@ -121,7 +118,7 @@ impl ApubObject for ApubComment {
cc: maa.ccs,
content: markdown_to_html(&self.content),
media_type: Some(MediaTypeHtml::Html),
- source: SourceCompat::Lemmy(Source::new(self.content.clone())),
+ source: Some(SourceCompat::new(self.content.clone())),
in_reply_to,
published: Some(convert_datetime(self.published)),
updated: self.updated.map(convert_datetime),
@@ -180,11 +177,7 @@ impl ApubObject for ApubComment {
.await?;
let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
- let content = if let SourceCompat::Lemmy(source) = ¬e.source {
- source.content.clone()
- } else {
- parse_html(¬e.content)
- };
+ let content = read_from_string_or_source(¬e.content, ¬e.source);
let content_slurs_removed = remove_slurs(&content, &context.settings().slur_regex());
let form = CommentForm {
@@ -219,6 +212,7 @@ pub(crate) mod tests {
protocol::tests::file_to_json_object,
};
use assert_json_diff::assert_json_include;
+ use html2md::parse_html;
use lemmy_db_schema::source::site::Site;
use serial_test::serial;
diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs
index 87646e91f..eb9cb218b 100644
--- a/crates/apub/src/objects/community.rs
+++ b/crates/apub/src/objects/community.rs
@@ -7,7 +7,7 @@ use crate::{
protocol::{
objects::{group::Group, tombstone::Tombstone, Endpoints},
ImageObject,
- Source,
+ SourceCompat,
},
};
use activitystreams_kinds::actor::GroupType;
@@ -85,9 +85,9 @@ impl ApubObject for ApubCommunity {
kind: GroupType::Group,
id: ObjectId::new(self.actor_id()),
preferred_username: self.name.clone(),
- name: self.title.clone(),
+ name: Some(self.title.clone()),
summary: self.description.as_ref().map(|b| markdown_to_html(b)),
- source: self.description.clone().map(Source::new),
+ source: self.description.clone().map(SourceCompat::new),
icon: self.icon.clone().map(ImageObject::new),
image: self.banner.clone().map(ImageObject::new),
sensitive: Some(self.nsfw),
diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs
index 9b5ef117d..9968b81e1 100644
--- a/crates/apub/src/objects/instance.rs
+++ b/crates/apub/src/objects/instance.rs
@@ -1,7 +1,7 @@
use crate::{
check_is_apub_id_valid,
- objects::{get_summary_from_string_or_source, verify_image_domain_matches},
- protocol::{objects::instance::Instance, ImageObject, Source},
+ objects::{read_from_string_or_source_opt, verify_image_domain_matches},
+ protocol::{objects::instance::Instance, ImageObject, SourceCompat},
};
use activitystreams_kinds::actor::ServiceType;
use chrono::NaiveDateTime;
@@ -77,7 +77,7 @@ impl ApubObject for ApubSite {
id: ObjectId::new(self.actor_id()),
name: self.name.clone(),
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
- source: self.sidebar.clone().map(Source::new),
+ source: self.sidebar.clone().map(SourceCompat::new),
summary: self.description.clone(),
media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html),
icon: self.icon.clone().map(ImageObject::new),
@@ -121,10 +121,7 @@ impl ApubObject for ApubSite {
) -> Result {
let site_form = SiteForm {
name: apub.name.clone(),
- sidebar: Some(get_summary_from_string_or_source(
- &apub.content,
- &apub.source,
- )),
+ sidebar: Some(read_from_string_or_source_opt(&apub.content, &apub.source)),
updated: apub.updated.map(|u| u.clone().naive_local()),
icon: Some(apub.icon.clone().map(|i| i.url.into())),
banner: Some(apub.image.clone().map(|i| i.url.into())),
diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs
index 6acbf9ad4..9f939aaa8 100644
--- a/crates/apub/src/objects/mod.rs
+++ b/crates/apub/src/objects/mod.rs
@@ -1,4 +1,4 @@
-use crate::protocol::{ImageObject, Source};
+use crate::protocol::{ImageObject, SourceCompat};
use html2md::parse_html;
use lemmy_apub_lib::verify::verify_domains_match;
use lemmy_utils::LemmyError;
@@ -11,12 +11,20 @@ pub mod person;
pub mod post;
pub mod private_message;
-pub(crate) fn get_summary_from_string_or_source(
+pub(crate) fn read_from_string_or_source(raw: &str, source: &Option) -> String {
+ if let Some(SourceCompat::Lemmy(s)) = source {
+ s.content.clone()
+ } else {
+ parse_html(raw)
+ }
+}
+
+pub(crate) fn read_from_string_or_source_opt(
raw: &Option,
- source: &Option,
+ source: &Option,
) -> Option {
- if let Some(source) = &source {
- Some(source.content.clone())
+ if let Some(SourceCompat::Lemmy(s2)) = source {
+ Some(s2.content.clone())
} else {
raw.as_ref().map(|s| parse_html(s))
}
diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs
index 26edc39b9..a903d5a65 100644
--- a/crates/apub/src/objects/person.rs
+++ b/crates/apub/src/objects/person.rs
@@ -2,8 +2,8 @@ use crate::{
check_is_apub_id_valid,
generate_outbox_url,
objects::{
- get_summary_from_string_or_source,
instance::fetch_instance_actor_for_object,
+ read_from_string_or_source_opt,
verify_image_domain_matches,
},
protocol::{
@@ -12,7 +12,7 @@ use crate::{
Endpoints,
},
ImageObject,
- Source,
+ SourceCompat,
},
};
use chrono::NaiveDateTime;
@@ -99,7 +99,7 @@ impl ApubObject for ApubPerson {
preferred_username: self.name.clone(),
name: self.display_name.clone(),
summary: self.bio.as_ref().map(|b| markdown_to_html(b)),
- source: self.bio.clone().map(Source::new),
+ source: self.bio.clone().map(SourceCompat::new),
icon: self.avatar.clone().map(ImageObject::new),
image: self.banner.clone().map(ImageObject::new),
matrix_user_id: self.matrix_user_id.clone(),
@@ -134,7 +134,7 @@ impl ApubObject for ApubPerson {
let slur_regex = &context.settings().slur_regex();
check_slurs(&person.preferred_username, slur_regex)?;
check_slurs_opt(&person.name, slur_regex)?;
- let bio = get_summary_from_string_or_source(&person.summary, &person.source);
+ let bio = read_from_string_or_source_opt(&person.summary, &person.source);
check_slurs_opt(&bio, slur_regex)?;
Ok(())
}
@@ -156,7 +156,7 @@ impl ApubObject for ApubPerson {
published: person.published.map(|u| u.naive_local()),
updated: person.updated.map(|u| u.naive_local()),
actor_id: Some(person.id.into()),
- bio: Some(get_summary_from_string_or_source(
+ bio: Some(read_from_string_or_source_opt(
&person.summary,
&person.source,
)),
diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs
index c7d48a686..d5309dc17 100644
--- a/crates/apub/src/objects/post.rs
+++ b/crates/apub/src/objects/post.rs
@@ -1,13 +1,14 @@
use crate::{
activities::{verify_is_public, verify_person_in_community},
check_is_apub_id_valid,
+ objects::read_from_string_or_source_opt,
protocol::{
objects::{
page::{Page, PageType},
tombstone::Tombstone,
},
ImageObject,
- Source,
+ SourceCompat,
},
};
use activitystreams_kinds::public;
@@ -16,7 +17,7 @@ use lemmy_api_common::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::ApubObject,
- values::{MediaTypeHtml, MediaTypeMarkdown},
+ values::MediaTypeHtml,
verify::verify_domains_match,
};
use lemmy_db_schema::{
@@ -100,12 +101,6 @@ impl ApubObject for ApubPost {
})
.await??;
- let source = self.body.clone().map(|body| Source {
- content: body,
- media_type: MediaTypeMarkdown::Markdown,
- });
- let image = self.thumbnail_url.clone().map(ImageObject::new);
-
let page = Page {
r#type: PageType::Page,
id: ObjectId::new(self.ap_id.clone()),
@@ -115,9 +110,9 @@ impl ApubObject for ApubPost {
name: self.name.clone(),
content: self.body.as_ref().map(|b| markdown_to_html(b)),
media_type: Some(MediaTypeHtml::Html),
- source,
+ source: self.body.clone().map(SourceCompat::new),
url: self.url.clone().map(|u| u.into()),
- image,
+ image: self.thumbnail_url.clone().map(ImageObject::new),
comments_enabled: Some(!self.locked),
sensitive: Some(self.nsfw),
stickied: Some(self.stickied),
@@ -175,10 +170,8 @@ impl ApubObject for ApubPost {
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));
- let body_slurs_removed = page
- .source
- .as_ref()
- .map(|s| remove_slurs(&s.content, &context.settings().slur_regex()));
+ let body_slurs_removed = read_from_string_or_source_opt(&page.content, &page.source)
+ .map(|s| remove_slurs(&s, &context.settings().slur_regex()));
let form = PostForm {
name: page.name,
url: page.url.map(|u| u.into()),
diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs
index 3768577cc..6f445184a 100644
--- a/crates/apub/src/objects/private_message.rs
+++ b/crates/apub/src/objects/private_message.rs
@@ -1,9 +1,11 @@
-use crate::protocol::{
- objects::chat_message::{ChatMessage, ChatMessageType},
- Source,
+use crate::{
+ objects::read_from_string_or_source,
+ protocol::{
+ objects::chat_message::{ChatMessage, ChatMessageType},
+ SourceCompat,
+ },
};
use chrono::NaiveDateTime;
-use html2md::parse_html;
use lemmy_api_common::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
@@ -88,7 +90,7 @@ impl ApubObject for ApubPrivateMessage {
to: [ObjectId::new(recipient.actor_id)],
content: markdown_to_html(&self.content),
media_type: Some(MediaTypeHtml::Html),
- source: Some(Source::new(self.content.clone())),
+ source: Some(SourceCompat::new(self.content.clone())),
published: Some(convert_datetime(self.published)),
updated: self.updated.map(convert_datetime),
};
@@ -131,16 +133,11 @@ impl ApubObject for ApubPrivateMessage {
let recipient = note.to[0]
.dereference(context, context.client(), request_counter)
.await?;
- let content = if let Some(source) = ¬e.source {
- source.content.clone()
- } else {
- parse_html(¬e.content)
- };
let form = PrivateMessageForm {
creator_id: creator.id,
recipient_id: recipient.id,
- content,
+ content: read_from_string_or_source(¬e.content, ¬e.source),
published: note.published.map(|u| u.naive_local()),
updated: note.updated.map(|u| u.naive_local()),
deleted: None,
diff --git a/crates/apub/src/protocol/activities/mod.rs b/crates/apub/src/protocol/activities/mod.rs
index 0f9509319..38c9e345d 100644
--- a/crates/apub/src/protocol/activities/mod.rs
+++ b/crates/apub/src/protocol/activities/mod.rs
@@ -21,6 +21,7 @@ mod tests {
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
deletion::delete::Delete,
following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
+ voting::vote::Vote,
},
tests::test_json,
};
@@ -55,4 +56,11 @@ mod tests {
fn test_parse_friendica_activities() {
test_json::("assets/friendica/activities/create_note.json").unwrap();
}
+
+ #[test]
+ fn test_parse_gnusocial_activities() {
+ test_json::("assets/gnusocial/activities/create_page.json").unwrap();
+ test_json::("assets/gnusocial/activities/create_note.json").unwrap();
+ test_json::("assets/gnusocial/activities/like_note.json").unwrap();
+ }
}
diff --git a/crates/apub/src/protocol/mod.rs b/crates/apub/src/protocol/mod.rs
index bb384de64..5f60e2b91 100644
--- a/crates/apub/src/protocol/mod.rs
+++ b/crates/apub/src/protocol/mod.rs
@@ -4,6 +4,7 @@ use url::Url;
use lemmy_apub_lib::values::MediaTypeMarkdown;
use lemmy_db_schema::newtypes::DbUrl;
+use serde_json::Value;
use std::collections::HashMap;
pub mod activities;
@@ -17,12 +18,20 @@ pub struct Source {
pub(crate) media_type: MediaTypeMarkdown,
}
-impl Source {
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+#[serde(untagged)]
+pub(crate) enum SourceCompat {
+ Lemmy(Source),
+ Other(Value),
+}
+
+impl SourceCompat {
pub(crate) fn new(content: String) -> Self {
- Source {
+ SourceCompat::Lemmy(Source {
content,
media_type: MediaTypeMarkdown::Markdown,
- }
+ })
}
}
diff --git a/crates/apub/src/protocol/objects/chat_message.rs b/crates/apub/src/protocol/objects/chat_message.rs
index a39f7b250..8cd37b59b 100644
--- a/crates/apub/src/protocol/objects/chat_message.rs
+++ b/crates/apub/src/protocol/objects/chat_message.rs
@@ -1,6 +1,6 @@
use crate::{
objects::{person::ApubPerson, private_message::ApubPrivateMessage},
- protocol::Source,
+ protocol::SourceCompat,
};
use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
@@ -19,7 +19,7 @@ pub struct ChatMessage {
pub(crate) content: String,
pub(crate) media_type: Option,
- pub(crate) source: Option,
+ pub(crate) source: Option,
pub(crate) published: Option>,
pub(crate) updated: Option>,
}
diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs
index 7820624d9..4114d4cfe 100644
--- a/crates/apub/src/protocol/objects/group.rs
+++ b/crates/apub/src/protocol/objects/group.rs
@@ -6,10 +6,10 @@ use crate::{
},
objects::{
community::ApubCommunity,
- get_summary_from_string_or_source,
+ read_from_string_or_source_opt,
verify_image_domain_matches,
},
- protocol::{objects::Endpoints, ImageObject, Source},
+ protocol::{objects::Endpoints, ImageObject, SourceCompat},
};
use activitystreams_kinds::actor::GroupType;
use chrono::{DateTime, FixedOffset};
@@ -33,14 +33,14 @@ pub struct Group {
pub(crate) id: ObjectId,
/// username, set at account creation and usually fixed after that
pub(crate) preferred_username: String,
- /// displayname
- pub(crate) name: String,
pub(crate) inbox: Url,
pub(crate) followers: Url,
pub(crate) public_key: PublicKey,
+ /// title
+ pub(crate) name: Option,
pub(crate) summary: Option,
- pub(crate) source: Option,
+ pub(crate) source: Option,
pub(crate) icon: Option,
/// banner
pub(crate) image: Option,
@@ -67,17 +67,17 @@ impl Group {
let slur_regex = &context.settings().slur_regex();
check_slurs(&self.preferred_username, slur_regex)?;
- check_slurs(&self.name, slur_regex)?;
- let description = get_summary_from_string_or_source(&self.summary, &self.source);
+ check_slurs_opt(&self.name, slur_regex)?;
+ let description = read_from_string_or_source_opt(&self.summary, &self.source);
check_slurs_opt(&description, slur_regex)?;
Ok(())
}
pub(crate) fn into_form(self) -> CommunityForm {
CommunityForm {
- name: self.preferred_username,
- title: self.name,
- description: get_summary_from_string_or_source(&self.summary, &self.source),
+ name: self.preferred_username.clone(),
+ title: self.name.unwrap_or(self.preferred_username),
+ description: read_from_string_or_source_opt(&self.summary, &self.source),
removed: None,
published: self.published.map(|u| u.naive_local()),
updated: self.updated.map(|u| u.naive_local()),
diff --git a/crates/apub/src/protocol/objects/instance.rs b/crates/apub/src/protocol/objects/instance.rs
index c70a780f4..b507d2991 100644
--- a/crates/apub/src/protocol/objects/instance.rs
+++ b/crates/apub/src/protocol/objects/instance.rs
@@ -1,6 +1,6 @@
use crate::{
objects::instance::ApubSite,
- protocol::{ImageObject, Source},
+ protocol::{ImageObject, SourceCompat},
};
use activitystreams_kinds::actor::ServiceType;
use chrono::{DateTime, FixedOffset};
@@ -25,7 +25,7 @@ pub struct Instance {
// sidebar
pub(crate) content: Option,
- pub(crate) source: Option,
+ pub(crate) source: Option,
// short instance description
pub(crate) summary: Option,
pub(crate) media_type: Option,
diff --git a/crates/apub/src/protocol/objects/mod.rs b/crates/apub/src/protocol/objects/mod.rs
index dfe502f3a..2d5f9be3a 100644
--- a/crates/apub/src/protocol/objects/mod.rs
+++ b/crates/apub/src/protocol/objects/mod.rs
@@ -74,4 +74,12 @@ mod tests {
test_json::("assets/friendica/objects/person.json").unwrap();
test_json::("assets/friendica/objects/note.json").unwrap();
}
+
+ #[test]
+ fn test_parse_object_gnusocial() {
+ test_json::("assets/gnusocial/objects/person.json").unwrap();
+ test_json::("assets/gnusocial/objects/group.json").unwrap();
+ test_json::("assets/gnusocial/objects/page.json").unwrap();
+ test_json::("assets/gnusocial/objects/note.json").unwrap();
+ }
}
diff --git a/crates/apub/src/protocol/objects/note.rs b/crates/apub/src/protocol/objects/note.rs
index d5c61c1f8..0aac5b854 100644
--- a/crates/apub/src/protocol/objects/note.rs
+++ b/crates/apub/src/protocol/objects/note.rs
@@ -2,7 +2,7 @@ use crate::{
fetcher::post_or_comment::PostOrComment,
mentions::Mention,
objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
- protocol::Source,
+ protocol::SourceCompat,
};
use activitystreams_kinds::object::NoteType;
use chrono::{DateTime, FixedOffset};
@@ -12,7 +12,6 @@ use lemmy_db_schema::{newtypes::CommentId, source::post::Post, traits::Crud};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
-use serde_json::Value;
use serde_with::skip_serializing_none;
use std::ops::Deref;
use url::Url;
@@ -33,30 +32,13 @@ pub struct Note {
pub(crate) in_reply_to: ObjectId,
pub(crate) media_type: Option,
- #[serde(default)]
- pub(crate) source: SourceCompat,
+ pub(crate) source: Option,
pub(crate) published: Option>,
pub(crate) updated: Option>,
#[serde(default)]
pub(crate) tag: Vec,
}
-/// Pleroma puts a raw string in the source, so we have to handle it here for deserialization to work
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-#[serde(untagged)]
-pub(crate) enum SourceCompat {
- Lemmy(Source),
- Other(Value),
- None,
-}
-
-impl Default for SourceCompat {
- fn default() -> Self {
- SourceCompat::None
- }
-}
-
impl Note {
pub(crate) async fn get_parents(
&self,
diff --git a/crates/apub/src/protocol/objects/page.rs b/crates/apub/src/protocol/objects/page.rs
index f6a282312..a8a8b7727 100644
--- a/crates/apub/src/protocol/objects/page.rs
+++ b/crates/apub/src/protocol/objects/page.rs
@@ -1,8 +1,9 @@
use crate::{
objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
- protocol::{ImageObject, Source},
+ protocol::{ImageObject, SourceCompat},
};
use chrono::{DateTime, FixedOffset};
+use itertools::Itertools;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
@@ -37,7 +38,7 @@ pub struct Page {
pub(crate) cc: Vec,
pub(crate) content: Option,
pub(crate) media_type: Option,
- pub(crate) source: Option,
+ pub(crate) source: Option,
pub(crate) url: Option,
pub(crate) image: Option,
pub(crate) comments_enabled: Option,
@@ -70,9 +71,9 @@ impl Page {
context: &LemmyContext,
request_counter: &mut i32,
) -> Result {
- let mut to_iter = self.to.iter();
+ let mut iter = self.to.iter().merge(self.cc.iter());
loop {
- if let Some(cid) = to_iter.next() {
+ if let Some(cid) = iter.next() {
let cid = ObjectId::new(cid.clone());
if let Ok(c) = cid
.dereference(context, context.client(), request_counter)
diff --git a/crates/apub/src/protocol/objects/person.rs b/crates/apub/src/protocol/objects/person.rs
index 0ab359dfd..bc45d9c30 100644
--- a/crates/apub/src/protocol/objects/person.rs
+++ b/crates/apub/src/protocol/objects/person.rs
@@ -1,6 +1,6 @@
use crate::{
objects::person::ApubPerson,
- protocol::{objects::Endpoints, ImageObject, Source},
+ protocol::{objects::Endpoints, ImageObject, SourceCompat},
};
use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey};
@@ -31,7 +31,7 @@ pub struct Person {
/// displayname
pub(crate) name: Option,
pub(crate) summary: Option,
- pub(crate) source: Option,
+ pub(crate) source: Option,
/// user avatar
pub(crate) icon: Option,
/// user banner