]> Untitled Git - lemmy.git/blobdiff - crates/apub/src/objects/comment.rs
Rewrite fetcher (#1792)
[lemmy.git] / crates / apub / src / objects / comment.rs
index c97ea994c6c43a1db1990fe7be1d9fb73546d5a8..f334487101fa108268f19362319993b226062aa1 100644 (file)
@@ -1,9 +1,11 @@
 use crate::{
   activities::verify_person_in_community,
   extensions::context::lemmy_context,
-  fetcher::objects::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
-  objects::{create_tombstone, get_or_fetch_and_upsert_person, FromApub, Source, ToApub},
+  fetcher::object_id::ObjectId,
+  migrations::CommentInReplyToMigration,
+  objects::{create_tombstone, FromApub, Source, ToApub},
   ActorType,
+  PostOrComment,
 };
 use activitystreams::{
   base::AnyBase,
@@ -18,7 +20,7 @@ use lemmy_apub_lib::{
   values::{MediaTypeHtml, MediaTypeMarkdown, PublicUrl},
   verify_domains_match,
 };
-use lemmy_db_queries::{ApubObject, Crud, DbPool};
+use lemmy_db_queries::{source::comment::Comment_, Crud, DbPool};
 use lemmy_db_schema::{
   source::{
     comment::{Comment, CommentForm},
@@ -35,16 +37,19 @@ use lemmy_utils::{
 };
 use lemmy_websocket::LemmyContext;
 use serde::{Deserialize, Serialize};
+use serde_with::skip_serializing_none;
+use std::ops::Deref;
 use url::Url;
 
+#[skip_serializing_none]
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct Note {
   #[serde(rename = "@context")]
   context: OneOrMany<AnyBase>,
   r#type: NoteType,
-  pub(crate) id: Url,
-  pub(crate) attributed_to: Url,
+  id: Url,
+  pub(crate) attributed_to: ObjectId<Person>,
   /// Indicates that the object is publicly readable. Unlike [`Post.to`], this one doesn't contain
   /// the community ID, as it would be incompatible with Pleroma (and we can get the community from
   /// the post in [`in_reply_to`]).
@@ -52,7 +57,7 @@ pub struct Note {
   content: String,
   media_type: MediaTypeHtml,
   source: Source,
-  in_reply_to: Vec<Url>,
+  in_reply_to: CommentInReplyToMigration,
   published: DateTime<FixedOffset>,
   updated: Option<DateTime<FixedOffset>>,
   #[serde(flatten)]
@@ -60,37 +65,58 @@ pub struct Note {
 }
 
 impl Note {
+  pub(crate) fn id_unchecked(&self) -> &Url {
+    &self.id
+  }
+  pub(crate) fn id(&self, expected_domain: &Url) -> Result<&Url, LemmyError> {
+    verify_domains_match(&self.id, expected_domain)?;
+    Ok(&self.id)
+  }
+
   async fn get_parents(
     &self,
     context: &LemmyContext,
     request_counter: &mut i32,
   ) -> Result<(Post, Option<CommentId>), LemmyError> {
-    // This post, or the parent comment might not yet exist on this server yet, fetch them.
-    let post_id = self.in_reply_to.get(0).context(location_info!())?;
-    let post = Box::pin(get_or_fetch_and_insert_post(
-      post_id,
-      context,
-      request_counter,
-    ))
-    .await?;
-
-    // The 2nd item, if it exists, is the parent comment apub_id
-    // Nested comments will automatically get fetched recursively
-    let parent_id: Option<CommentId> = match self.in_reply_to.get(1) {
-      Some(parent_comment_uri) => {
-        let parent_comment = Box::pin(get_or_fetch_and_insert_comment(
-          parent_comment_uri,
-          context,
-          request_counter,
-        ))
-        .await?;
-
-        Some(parent_comment.id)
+    match &self.in_reply_to {
+      CommentInReplyToMigration::Old(in_reply_to) => {
+        // This post, or the parent comment might not yet exist on this server yet, fetch them.
+        let post_id = in_reply_to.get(0).context(location_info!())?;
+        let post_id = ObjectId::new(post_id.clone());
+        let post = Box::pin(post_id.dereference(context, request_counter)).await?;
+
+        // The 2nd item, if it exists, is the parent comment apub_id
+        // Nested comments will automatically get fetched recursively
+        let parent_id: Option<CommentId> = match in_reply_to.get(1) {
+          Some(comment_id) => {
+            let comment_id = ObjectId::<Comment>::new(comment_id.clone());
+            let parent_comment = Box::pin(comment_id.dereference(context, request_counter)).await?;
+
+            Some(parent_comment.id)
+          }
+          None => None,
+        };
+
+        Ok((post, parent_id))
       }
-      None => None,
-    };
-
-    Ok((post, parent_id))
+      CommentInReplyToMigration::New(in_reply_to) => {
+        let parent = Box::pin(in_reply_to.dereference(context, request_counter).await?);
+        match parent.deref() {
+          PostOrComment::Post(p) => {
+            // Workaround because I cant figure ut how to get the post out of the box (and we dont
+            // want to stackoverflow in a deep comment hierarchy).
+            let post_id = p.id;
+            let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+            Ok((post, None))
+          }
+          PostOrComment::Comment(c) => {
+            let post_id = c.post_id;
+            let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+            Ok((post, Some(c.id)))
+          }
+        }
+      }
+    }
   }
 
   pub(crate) async fn verify(
@@ -108,10 +134,10 @@ impl Note {
     if post.locked {
       return Err(anyhow!("Post is locked").into());
     }
-    verify_domains_match(&self.attributed_to, &self.id)?;
+    verify_domains_match(self.attributed_to.inner(), &self.id)?;
     verify_person_in_community(
       &self.attributed_to,
-      &community.actor_id(),
+      &ObjectId::new(community.actor_id()),
       context,
       request_counter,
     )
@@ -145,7 +171,7 @@ impl ToApub for Comment {
       context: lemmy_context(),
       r#type: NoteType::Note,
       id: self.ap_id.to_owned().into_inner(),
-      attributed_to: creator.actor_id.into_inner(),
+      attributed_to: ObjectId::new(creator.actor_id),
       to: PublicUrl::Public,
       content: self.content.clone(),
       media_type: MediaTypeHtml::Html,
@@ -153,7 +179,7 @@ impl ToApub for Comment {
         content: self.content.clone(),
         media_type: MediaTypeMarkdown::Markdown,
       },
-      in_reply_to: in_reply_to_vec,
+      in_reply_to: CommentInReplyToMigration::Old(in_reply_to_vec),
       published: convert_datetime(self.published),
       updated: self.updated.map(convert_datetime),
       unparsed: Default::default(),
@@ -182,13 +208,18 @@ impl FromApub for Comment {
   async fn from_apub(
     note: &Note,
     context: &LemmyContext,
-    _expected_domain: Url,
+    expected_domain: &Url,
     request_counter: &mut i32,
-    _mod_action_allowed: bool,
   ) -> Result<Comment, LemmyError> {
-    let creator =
-      get_or_fetch_and_upsert_person(&note.attributed_to, context, request_counter).await?;
+    let ap_id = Some(note.id(expected_domain)?.clone().into());
+    let creator = note
+      .attributed_to
+      .dereference(context, request_counter)
+      .await?;
     let (post, parent_comment_id) = note.get_parents(context, request_counter).await?;
+    if post.locked {
+      return Err(anyhow!("Post is locked").into());
+    }
 
     let content = &note.source.content;
     let content_slurs_removed = remove_slurs(content);
@@ -203,7 +234,7 @@ impl FromApub for Comment {
       published: Some(note.published.naive_local()),
       updated: note.updated.map(|u| u.to_owned().naive_local()),
       deleted: None,
-      ap_id: Some(note.id.clone().into()),
+      ap_id,
       local: Some(false),
     };
     Ok(blocking(context.pool(), move |conn| Comment::upsert(conn, &form)).await??)