--- /dev/null
+{
+ "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"
+ ]
+}
--- /dev/null
+{
+ "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"
+ ]
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "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"
+}
--- /dev/null
+{
+ "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"
+ }
+}
--- /dev/null
+{
+ "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"
+ ]
+}
--- /dev/null
+{
+ "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"
+ ]
+}
--- /dev/null
+{
+ "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"
+ }
+}
{
"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"
{
"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"
{
"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"
{
"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"
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,
)?;
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(),
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,
) -> 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(),
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,
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),
.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 {
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;
protocol::{
objects::{group::Group, tombstone::Tombstone, Endpoints},
ImageObject,
- Source,
+ SourceCompat,
},
};
use activitystreams_kinds::actor::GroupType;
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),
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;
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),
) -> 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())),
-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;
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))
}
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::{
Endpoints,
},
ImageObject,
- Source,
+ SourceCompat,
},
};
use chrono::NaiveDateTime;
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(),
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(())
}
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,
)),
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;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::ApubObject,
- values::{MediaTypeHtml, MediaTypeMarkdown},
+ values::MediaTypeHtml,
verify::verify_domains_match,
};
use lemmy_db_schema::{
})
.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()),
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),
.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()),
-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,
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),
};
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,
create_or_update::{comment::CreateOrUpdateComment, post::CreateOrUpdatePost},
deletion::delete::Delete,
following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
+ voting::vote::Vote,
},
tests::test_json,
};
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();
+ }
}
use lemmy_apub_lib::values::MediaTypeMarkdown;
use lemmy_db_schema::newtypes::DbUrl;
+use serde_json::Value;
use std::collections::HashMap;
pub mod activities;
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,
- }
+ })
}
}
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};
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>>,
}
},
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};
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>,
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()),
use crate::{
objects::instance::ApubSite,
- protocol::{ImageObject, Source},
+ protocol::{ImageObject, SourceCompat},
};
use activitystreams_kinds::actor::ServiceType;
use chrono::{DateTime, FixedOffset};
// 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>,
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();
+ }
}
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};
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;
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,
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,
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>,
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)
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};
/// 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