]> Untitled Git - lemmy.git/commitdiff
Migrate towards using page.attachment field for url (ref #2144) (#2182)
authorNutomic <me@nutomic.com>
Fri, 1 Apr 2022 18:25:19 +0000 (18:25 +0000)
committerGitHub <noreply@github.com>
Fri, 1 Apr 2022 18:25:19 +0000 (18:25 +0000)
23 files changed:
Cargo.lock
crates/apub/Cargo.toml
crates/apub/assets/lemmy/activities/create_or_update/create_page.json
crates/apub/assets/lemmy/activities/create_or_update/update_page.json
crates/apub/assets/lemmy/objects/page.json
crates/apub/src/activities/create_or_update/post.rs
crates/apub/src/activity_lists.rs
crates/apub/src/fetcher/post_or_comment.rs
crates/apub/src/lib.rs
crates/apub/src/objects/comment.rs
crates/apub/src/objects/community.rs
crates/apub/src/objects/instance.rs
crates/apub/src/objects/mod.rs
crates/apub/src/objects/person.rs
crates/apub/src/objects/post.rs
crates/apub/src/objects/private_message.rs
crates/apub/src/protocol/mod.rs
crates/apub/src/protocol/objects/chat_message.rs
crates/apub/src/protocol/objects/group.rs
crates/apub/src/protocol/objects/instance.rs
crates/apub/src/protocol/objects/note.rs
crates/apub/src/protocol/objects/page.rs
crates/apub/src/protocol/objects/person.rs

index 907b489cf31754c0eaaa7127b015c809eaa8de76..cf16d2e42d0834d83668031a9e442e59a02a86bc 100644 (file)
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "activitystreams-kinds"
-version = "0.1.2"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0784e99afd032199d3ed70cefb8eb3a8d1aef15f7f2c4e68d033c4e12bb6079e"
+checksum = "6d014a4fb8828870b7b46bee6257b9a89d06188ae8d435381ba94f14c8c697d8"
 dependencies = [
  "serde",
  "url",
index 51165ea9cce489126304df42bf6263aba41a95ef..4f7338df014c67898796ef91074761a97c26cf5e 100644 (file)
@@ -21,7 +21,7 @@ lemmy_db_views_actor = { version = "=0.16.2", path = "../db_views_actor" }
 lemmy_api_common = { version = "=0.16.2", path = "../api_common" }
 lemmy_websocket = { version = "=0.16.2", path = "../websocket" }
 diesel = "1.4.8"
-activitystreams-kinds = "0.1.2"
+activitystreams-kinds = "0.2.1"
 bcrypt = "0.10.1"
 chrono = { version = "0.4.19", features = ["serde"] }
 serde_json = { version = "1.0.72", features = ["preserve_order"] }
index b223120b06f812a7ca9ce3ed5c32fa3749006532..37718b234da04888e4e6205d50279f6e3856098e 100644 (file)
       "mediaType": "text/markdown"
     },
     "url": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg",
+    "attachment": [
+      {
+        "type": "Link",
+        "href": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg"
+      }
+    ],
     "commentsEnabled": true,
     "sensitive": false,
     "stickied": false,
index beadfa0d1f1262bbade487d26130d3845e263bad..7cde6cdd900d7c2a43a972390b3d4aa78d8667c9 100644 (file)
       "mediaType": "text/markdown"
     },
     "url": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg",
+    "attachment": [
+      {
+        "type": "Link",
+        "href": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg"
+      }
+    ],
     "commentsEnabled": true,
     "sensitive": false,
     "stickied": false,
index 36cac596f5f11ab416cb42cd69b276c741710296..b90ee549a12ee4c012c0d6288cdb043f19181a9d 100644 (file)
     "mediaType": "text/markdown"
   },
   "url": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png",
+  "attachment": [
+    {
+      "type": "Link",
+      "href": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png"
+    }
+  ],
   "image": {
     "type": "Image",
     "url": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png"
index 242637768718b95c678b98000a96c96c3d56d4b2..9fd12b37e317bd0bbca14f677890a8fe4184dfb1 100644 (file)
@@ -63,7 +63,7 @@ impl CreateOrUpdatePost {
 
     let create_or_update = CreateOrUpdatePost::new(post, actor, &community, kind, context).await?;
     let id = create_or_update.id.clone();
-    let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
+    let activity = AnnouncableActivities::CreateOrUpdatePost(Box::new(create_or_update));
     send_activity_in_community(activity, &id, actor, &community, vec![], context).await
   }
 }
index a24ac8e4851e1ae5cc9f32fc9f7c15b7eea256a7..362d29afb9224015eb068f5bb96eae8879da0af8 100644 (file)
@@ -70,7 +70,7 @@ pub enum PersonInboxActivities {
 #[activity_handler(LemmyContext)]
 pub enum AnnouncableActivities {
   CreateOrUpdateComment(CreateOrUpdateComment),
-  CreateOrUpdatePost(CreateOrUpdatePost),
+  CreateOrUpdatePost(Box<CreateOrUpdatePost>),
   Vote(Vote),
   UndoVote(UndoVote),
   Delete(Delete),
index f03a113ecd4b832a2e3a08981edacbd86feeea12..eaebeca6b736f14664a6cff59008cba3c5569fbd 100644 (file)
@@ -18,7 +18,7 @@ pub enum PostOrComment {
 #[derive(Deserialize)]
 #[serde(untagged)]
 pub enum PageOrNote {
-  Page(Page),
+  Page(Box<Page>),
   Note(Note),
 }
 
@@ -85,7 +85,7 @@ impl ApubObject for PostOrComment {
   ) -> Result<Self, LemmyError> {
     Ok(match apub {
       PageOrNote::Page(p) => PostOrComment::Post(Box::new(
-        ApubPost::from_apub(p, context, request_counter).await?,
+        ApubPost::from_apub(*p, context, request_counter).await?,
       )),
       PageOrNote::Note(n) => PostOrComment::Comment(Box::new(
         ApubComment::from_apub(n, context, request_counter).await?,
index 7a66e8aa28740ef5d7e33891a00b33fbda8ec719..80116a8f87d136715f2086b41b5d1dbfe339215a 100644 (file)
@@ -130,6 +130,18 @@ where
   })
 }
 
+pub(crate) fn deserialize_skip_error<'de, T, D>(deserializer: D) -> Result<T, D::Error>
+where
+  T: Deserialize<'de> + Default,
+  D: Deserializer<'de>,
+{
+  let result = Deserialize::deserialize(deserializer);
+  Ok(match result {
+    Ok(o) => o,
+    Err(_) => Default::default(),
+  })
+}
+
 pub enum EndpointType {
   Community,
   Person,
index c622c14dd78ef278754388b0f2091228423708c2..23a645f71ba6119f9442538038c47d302e397a5a 100644 (file)
@@ -5,7 +5,7 @@ use crate::{
   objects::read_from_string_or_source,
   protocol::{
     objects::{note::Note, tombstone::Tombstone},
-    SourceCompat,
+    Source,
   },
   PostOrComment,
 };
@@ -118,7 +118,7 @@ impl ApubObject for ApubComment {
       cc: maa.ccs,
       content: markdown_to_html(&self.content),
       media_type: Some(MediaTypeHtml::Html),
-      source: Some(SourceCompat::new(self.content.clone())),
+      source: Some(Source::new(self.content.clone())),
       in_reply_to,
       published: Some(convert_datetime(self.published)),
       updated: self.updated.map(convert_datetime),
index bbb239cb57a949a4c99b982ce3eb6ca317b81fc6..342a4080e198b5d18a336fe275693c942fbf9589 100644 (file)
@@ -7,7 +7,7 @@ use crate::{
   protocol::{
     objects::{group::Group, tombstone::Tombstone, Endpoints},
     ImageObject,
-    SourceCompat,
+    Source,
   },
 };
 use activitystreams_kinds::actor::GroupType;
@@ -87,7 +87,7 @@ impl ApubObject for ApubCommunity {
       preferred_username: self.name.clone(),
       name: Some(self.title.clone()),
       summary: self.description.as_ref().map(|b| markdown_to_html(b)),
-      source: self.description.clone().map(SourceCompat::new),
+      source: self.description.clone().map(Source::new),
       icon: self.icon.clone().map(ImageObject::new),
       image: self.banner.clone().map(ImageObject::new),
       sensitive: Some(self.nsfw),
index af75812dacfc406e79da3c21d30eabe92e840d69..fbd0bed966271a4c575f7803c1386e4cba163ead 100644 (file)
@@ -1,7 +1,7 @@
 use crate::{
   check_is_apub_id_valid,
   objects::{read_from_string_or_source_opt, verify_image_domain_matches},
-  protocol::{objects::instance::Instance, ImageObject, SourceCompat},
+  protocol::{objects::instance::Instance, ImageObject, Source},
 };
 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(SourceCompat::new),
+      source: self.sidebar.clone().map(Source::new),
       summary: self.description.clone(),
       media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html),
       icon: self.icon.clone().map(ImageObject::new),
index b387564a78abd57bc38fc34ccac9d507b537cfa2..78013b0cc39e01a1a6249aa6c155f4530b2d2a26 100644 (file)
@@ -1,4 +1,4 @@
-use crate::protocol::{ImageObject, SourceCompat};
+use crate::protocol::{ImageObject, Source};
 use html2md::parse_html;
 use lemmy_apub_lib::verify::verify_domains_match;
 use lemmy_utils::LemmyError;
@@ -11,8 +11,8 @@ pub mod person;
 pub mod post;
 pub mod private_message;
 
-pub(crate) fn read_from_string_or_source(raw: &str, source: &Option<SourceCompat>) -> String {
-  if let Some(SourceCompat::Lemmy(s)) = source {
+pub(crate) fn read_from_string_or_source(raw: &str, source: &Option<Source>) -> String {
+  if let Some(s) = source {
     s.content.clone()
   } else {
     parse_html(raw)
@@ -21,9 +21,9 @@ pub(crate) fn read_from_string_or_source(raw: &str, source: &Option<SourceCompat
 
 pub(crate) fn read_from_string_or_source_opt(
   raw: &Option<String>,
-  source: &Option<SourceCompat>,
+  source: &Option<Source>,
 ) -> Option<String> {
-  if let Some(SourceCompat::Lemmy(s2)) = source {
+  if let Some(s2) = source {
     Some(s2.content.clone())
   } else {
     raw.as_ref().map(|s| parse_html(s))
index a6133ed47f9df6fd0a7dd1ae1f7e7e5417c7af03..039dbbb131c538d19a817eb93263e2576352afd3 100644 (file)
@@ -12,7 +12,7 @@ use crate::{
       Endpoints,
     },
     ImageObject,
-    SourceCompat,
+    Source,
   },
 };
 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(SourceCompat::new),
+      source: self.bio.clone().map(Source::new),
       icon: self.avatar.clone().map(ImageObject::new),
       image: self.banner.clone().map(ImageObject::new),
       matrix_user_id: self.matrix_user_id.clone(),
index dbea0349c077c3e77fe7df403d7b63bc2526479f..b5fbe9424114f23b13699a586a3fc162410b77a2 100644 (file)
@@ -4,11 +4,11 @@ use crate::{
   objects::read_from_string_or_source_opt,
   protocol::{
     objects::{
-      page::{Page, PageType},
+      page::{Attachment, Page, PageType},
       tombstone::Tombstone,
     },
     ImageObject,
-    SourceCompat,
+    Source,
   },
 };
 use activitystreams_kinds::public;
@@ -110,8 +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: self.body.clone().map(SourceCompat::new),
+      source: self.body.clone().map(Source::new),
       url: self.url.clone().map(|u| u.into()),
+      attachment: self.url.clone().map(Attachment::new).into_iter().collect(),
       image: self.thumbnail_url.clone().map(ImageObject::new),
       comments_enabled: Some(!self.locked),
       sensitive: Some(self.nsfw),
@@ -160,8 +161,13 @@ impl ApubObject for ApubPost {
       .await?;
     let community = page.extract_community(context, request_counter).await?;
 
+    let url = if let Some(attachment) = page.attachment.first() {
+      Some(attachment.href.clone())
+    } else {
+      page.url
+    };
     let thumbnail_url: Option<Url> = page.image.map(|i| i.url);
-    let (metadata_res, pictrs_thumbnail) = if let Some(url) = &page.url {
+    let (metadata_res, pictrs_thumbnail) = if let Some(url) = &url {
       fetch_site_data(context.client(), &context.settings(), Some(url)).await
     } else {
       (None, thumbnail_url)
@@ -173,8 +179,8 @@ impl ApubObject for ApubPost {
     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()),
+      name: page.name.clone(),
+      url: url.map(Into::into),
       body: body_slurs_removed,
       creator_id: creator.id,
       community_id: community.id,
index 04974b802203e7c1f77c042e8eb06fe426ae8f2c..560059865cbdd54243e818fca131f00293379200 100644 (file)
@@ -2,7 +2,7 @@ use crate::{
   objects::read_from_string_or_source,
   protocol::{
     objects::chat_message::{ChatMessage, ChatMessageType},
-    SourceCompat,
+    Source,
   },
 };
 use chrono::NaiveDateTime;
@@ -90,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(SourceCompat::new(self.content.clone())),
+      source: Some(Source::new(self.content.clone())),
       published: Some(convert_datetime(self.published)),
       updated: self.updated.map(convert_datetime),
     };
index 5f60e2b9139d042e44660a4e85c3ea039aafba02..ea56cda1f00e2ca505a78bec089d2e7ba6fdc407 100644 (file)
@@ -1,11 +1,9 @@
 use activitystreams_kinds::object::ImageType;
-use serde::{Deserialize, Serialize};
-use url::Url;
-
 use lemmy_apub_lib::values::MediaTypeMarkdown;
 use lemmy_db_schema::newtypes::DbUrl;
-use serde_json::Value;
+use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
+use url::Url;
 
 pub mod activities;
 pub(crate) mod collections;
@@ -18,20 +16,12 @@ pub struct Source {
   pub(crate) media_type: MediaTypeMarkdown,
 }
 
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-#[serde(untagged)]
-pub(crate) enum SourceCompat {
-  Lemmy(Source),
-  Other(Value),
-}
-
-impl SourceCompat {
+impl Source {
   pub(crate) fn new(content: String) -> Self {
-    SourceCompat::Lemmy(Source {
+    Source {
       content,
       media_type: MediaTypeMarkdown::Markdown,
-    })
+    }
   }
 }
 
index 8cd37b59b4f98cf686ea33af5054cd25c30a90b7..163bff3a4918a4452042e3eccdf8e889c683193c 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::{person::ApubPerson, private_message::ApubPrivateMessage},
-  protocol::SourceCompat,
+  protocol::Source,
 };
 use chrono::{DateTime, FixedOffset};
 use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
@@ -19,7 +19,9 @@ pub struct ChatMessage {
   pub(crate) content: String,
 
   pub(crate) media_type: Option<MediaTypeHtml>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
   pub(crate) published: Option<DateTime<FixedOffset>>,
   pub(crate) updated: Option<DateTime<FixedOffset>>,
 }
index 4114d4cfede77a7d139b078c9f35288a734ddb41..410c9e87f6148cc89d57f9e5c0affd990816a37f 100644 (file)
@@ -9,7 +9,7 @@ use crate::{
     read_from_string_or_source_opt,
     verify_image_domain_matches,
   },
-  protocol::{objects::Endpoints, ImageObject, SourceCompat},
+  protocol::{objects::Endpoints, ImageObject, Source},
 };
 use activitystreams_kinds::actor::GroupType;
 use chrono::{DateTime, FixedOffset};
@@ -40,7 +40,9 @@ pub struct Group {
   /// title
   pub(crate) name: Option<String>,
   pub(crate) summary: Option<String>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
   pub(crate) icon: Option<ImageObject>,
   /// banner
   pub(crate) image: Option<ImageObject>,
index b507d2991ccfa4a5885940103874ed6eab131b6e..ee3a0a96e6a30ec32d108725149c33e33b168a3d 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::instance::ApubSite,
-  protocol::{ImageObject, SourceCompat},
+  protocol::{ImageObject, Source},
 };
 use activitystreams_kinds::actor::ServiceType;
 use chrono::{DateTime, FixedOffset};
@@ -25,7 +25,9 @@ pub struct Instance {
 
   // sidebar
   pub(crate) content: Option<String>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
   // short instance description
   pub(crate) summary: Option<String>,
   pub(crate) media_type: Option<MediaTypeHtml>,
index 0aac5b854a469168a9e897880e3ebbb43b8888ca..dc7b99b86ec550c970f3679e5ddd00b830454494 100644 (file)
@@ -2,7 +2,7 @@ use crate::{
   fetcher::post_or_comment::PostOrComment,
   mentions::Mention,
   objects::{comment::ApubComment, person::ApubPerson, post::ApubPost},
-  protocol::SourceCompat,
+  protocol::Source,
 };
 use activitystreams_kinds::object::NoteType;
 use chrono::{DateTime, FixedOffset};
@@ -32,7 +32,9 @@ pub struct Note {
   pub(crate) in_reply_to: ObjectId<PostOrComment>,
 
   pub(crate) media_type: Option<MediaTypeHtml>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
   pub(crate) published: Option<DateTime<FixedOffset>>,
   pub(crate) updated: Option<DateTime<FixedOffset>>,
   #[serde(default)]
index 58b39226dceaae97485ca14dfda2c15a76272171..987a7d75019fd29b696bf464bd3c4377b1bb9585 100644 (file)
@@ -1,7 +1,8 @@
 use crate::{
   objects::{community::ApubCommunity, person::ApubPerson, post::ApubPost},
-  protocol::{ImageObject, SourceCompat},
+  protocol::{ImageObject, Source},
 };
+use activitystreams_kinds::link::LinkType;
 use chrono::{DateTime, FixedOffset};
 use itertools::Itertools;
 use lemmy_apub_lib::{
@@ -10,6 +11,7 @@ use lemmy_apub_lib::{
   traits::{ActivityHandler, ApubObject},
   values::MediaTypeHtml,
 };
+use lemmy_db_schema::newtypes::DbUrl;
 use lemmy_utils::LemmyError;
 use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
@@ -39,8 +41,15 @@ pub struct Page {
   pub(crate) cc: Vec<Url>,
   pub(crate) content: Option<String>,
   pub(crate) media_type: Option<MediaTypeHtml>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
+  /// deprecated, use attachment field
   pub(crate) url: Option<Url>,
+  /// most software uses array type for attachment field, so we do the same. nevertheless, we only
+  /// use the first item
+  #[serde(default)]
+  pub(crate) attachment: Vec<Attachment>,
   pub(crate) image: Option<ImageObject>,
   pub(crate) comments_enabled: Option<bool>,
   pub(crate) sensitive: Option<bool>,
@@ -49,6 +58,13 @@ pub struct Page {
   pub(crate) updated: Option<DateTime<FixedOffset>>,
 }
 
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Attachment {
+  pub(crate) href: Url,
+  pub(crate) r#type: LinkType,
+}
+
 impl Page {
   /// Only mods can change the post's stickied/locked status. So if either of these is changed from
   /// the current value, it is a mod action and needs to be verified as such.
@@ -89,6 +105,15 @@ impl Page {
   }
 }
 
+impl Attachment {
+  pub(crate) fn new(url: DbUrl) -> Attachment {
+    Attachment {
+      href: url.into(),
+      r#type: Default::default(),
+    }
+  }
+}
+
 // Used for community outbox, so that it can be compatible with Pleroma/Mastodon.
 #[async_trait::async_trait(?Send)]
 impl ActivityHandler for Page {
index bc45d9c308dcdb7f69cf3741707d3b0114a9531e..f69b1ad646ce2e71280ad394797b36d5f81d3195 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{
   objects::person::ApubPerson,
-  protocol::{objects::Endpoints, ImageObject, SourceCompat},
+  protocol::{objects::Endpoints, ImageObject, Source},
 };
 use chrono::{DateTime, FixedOffset};
 use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey};
@@ -31,7 +31,9 @@ pub struct Person {
   /// displayname
   pub(crate) name: Option<String>,
   pub(crate) summary: Option<String>,
-  pub(crate) source: Option<SourceCompat>,
+  #[serde(default)]
+  #[serde(deserialize_with = "crate::deserialize_skip_error")]
+  pub(crate) source: Option<Source>,
   /// user avatar
   pub(crate) icon: Option<ImageObject>,
   /// user banner