mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 19:31:05 +00:00
GNU social compatibility (#2100)
* Use SourceCompat everywhere (better compat with other software) * Name field should not be mandatory in Group * also check page.cc field for community id * add gnu social tests * better to use option<sourcecompat> * update gnu social tests, marked vote as "unlisted"
This commit is contained in:
parent
1e9f609cdb
commit
dfb0938738
29 changed files with 409 additions and 116 deletions
53
crates/apub/assets/gnusocial/activities/create_note.json
Normal file
53
crates/apub/assets/gnusocial/activities/create_note.json
Normal file
|
@ -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": "<p>yay ^^</p>",
|
||||
"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"
|
||||
]
|
||||
}
|
53
crates/apub/assets/gnusocial/activities/create_page.json
Normal file
53
crates/apub/assets/gnusocial/activities/create_page.json
Normal file
|
@ -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": "<p>This is an interesting page.</p>",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
16
crates/apub/assets/gnusocial/activities/like_note.json
Normal file
16
crates/apub/assets/gnusocial/activities/like_note.json
Normal file
|
@ -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"
|
||||
}
|
42
crates/apub/assets/gnusocial/objects/group.json
Normal file
42
crates/apub/assets/gnusocial/objects/group.json
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
44
crates/apub/assets/gnusocial/objects/note.json
Normal file
44
crates/apub/assets/gnusocial/objects/note.json
Normal file
|
@ -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": "<p>yay ^^</p>",
|
||||
"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"
|
||||
]
|
||||
}
|
41
crates/apub/assets/gnusocial/objects/page.json
Normal file
41
crates/apub/assets/gnusocial/objects/page.json
Normal file
|
@ -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": "<p>This is an interesting page.</p>",
|
||||
"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"
|
||||
]
|
||||
}
|
42
crates/apub/assets/gnusocial/objects/person.json
Normal file
42
crates/apub/assets/gnusocial/objects/person.json
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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<Vote, LemmyError> {
|
||||
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(),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<Self, LemmyError> {
|
||||
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())),
|
||||
|
|
|
@ -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<SourceCompat>) -> 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<String>,
|
||||
source: &Option<Source>,
|
||||
source: &Option<SourceCompat>,
|
||||
) -> Option<String> {
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)),
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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::<CreateOrUpdateComment>("assets/friendica/activities/create_note.json").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_gnusocial_activities() {
|
||||
test_json::<CreateOrUpdatePost>("assets/gnusocial/activities/create_page.json").unwrap();
|
||||
test_json::<CreateOrUpdateComment>("assets/gnusocial/activities/create_note.json").unwrap();
|
||||
test_json::<Vote>("assets/gnusocial/activities/like_note.json").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MediaTypeHtml>,
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
pub(crate) published: Option<DateTime<FixedOffset>>,
|
||||
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
||||
}
|
||||
|
|
|
@ -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<ApubCommunity>,
|
||||
/// 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<String>,
|
||||
pub(crate) summary: Option<String>,
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
pub(crate) icon: Option<ImageObject>,
|
||||
/// banner
|
||||
pub(crate) image: Option<ImageObject>,
|
||||
|
@ -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()),
|
||||
|
|
|
@ -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<String>,
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
// short instance description
|
||||
pub(crate) summary: Option<String>,
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
|
|
|
@ -74,4 +74,12 @@ mod tests {
|
|||
test_json::<Person>("assets/friendica/objects/person.json").unwrap();
|
||||
test_json::<Note>("assets/friendica/objects/note.json").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_object_gnusocial() {
|
||||
test_json::<Person>("assets/gnusocial/objects/person.json").unwrap();
|
||||
test_json::<Group>("assets/gnusocial/objects/group.json").unwrap();
|
||||
test_json::<Page>("assets/gnusocial/objects/page.json").unwrap();
|
||||
test_json::<Note>("assets/gnusocial/objects/note.json").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PostOrComment>,
|
||||
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
#[serde(default)]
|
||||
pub(crate) source: SourceCompat,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
pub(crate) published: Option<DateTime<FixedOffset>>,
|
||||
pub(crate) updated: Option<DateTime<FixedOffset>>,
|
||||
#[serde(default)]
|
||||
pub(crate) tag: Vec<Mention>,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
|
|
|
@ -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<Url>,
|
||||
pub(crate) content: Option<String>,
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
pub(crate) url: Option<Url>,
|
||||
pub(crate) image: Option<ImageObject>,
|
||||
pub(crate) comments_enabled: Option<bool>,
|
||||
|
@ -70,9 +71,9 @@ impl Page {
|
|||
context: &LemmyContext,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<ApubCommunity, LemmyError> {
|
||||
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)
|
||||
|
|
|
@ -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<String>,
|
||||
pub(crate) summary: Option<String>,
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) source: Option<SourceCompat>,
|
||||
/// user avatar
|
||||
pub(crate) icon: Option<ImageObject>,
|
||||
/// user banner
|
||||
|
|
Loading…
Reference in a new issue