diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index bf8de1ebd..89baf997d 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -2,7 +2,6 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_comment, ActorType, - FromApub, NoteExt, }; use activitystreams::{ @@ -20,6 +19,7 @@ use lemmy_db::{ use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs}; use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; +use crate::objects::FromApub; pub(crate) async fn receive_create_comment( create: Create, diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index f44604cc1..b859e1c5a 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,9 +1,9 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_comment, - FromApub, NoteExt, }; +use crate::objects::FromApub; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index 80044237f..785a3a1ea 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -2,9 +2,9 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_post, ActorType, - FromApub, PageExt, }; +use crate::objects::FromApub; use activitystreams::{ activity::{Create, Dislike, Like, Remove, Update}, prelude::*, diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index 99d0ed1d9..12ed266f6 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,9 +1,9 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_post, - FromApub, PageExt, }; +use crate::objects::FromApub; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ diff --git a/lemmy_apub/src/activities/receive/private_message.rs b/lemmy_apub/src/activities/receive/private_message.rs index 8f1c95b9d..a954d62d6 100644 --- a/lemmy_apub/src/activities/receive/private_message.rs +++ b/lemmy_apub/src/activities/receive/private_message.rs @@ -3,9 +3,9 @@ use crate::{ check_is_apub_id_valid, fetcher::get_or_fetch_and_upsert_user, inbox::get_activity_to_and_cc, - FromApub, NoteExt, }; +use crate::objects::FromApub; use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Delete, Undo, Update}, base::{AsBase, ExtendsExt}, diff --git a/lemmy_apub/src/activities/send/comment.rs b/lemmy_apub/src/activities/send/comment.rs index 2aee7b6e3..856ad8fc6 100644 --- a/lemmy_apub/src/activities/send/comment.rs +++ b/lemmy_apub/src/activities/send/comment.rs @@ -6,7 +6,6 @@ use crate::{ ActorType, ApubLikeableType, ApubObjectType, - ToApub, }; use activitystreams::{ activity::{ @@ -39,6 +38,7 @@ use log::debug; use reqwest::Client; use serde_json::Error; use url::Url; +use crate::objects::ToApub; #[async_trait::async_trait(?Send)] impl ApubObjectType for Comment { diff --git a/lemmy_apub/src/activities/send/post.rs b/lemmy_apub/src/activities/send/post.rs index da78667f0..9e42a269e 100644 --- a/lemmy_apub/src/activities/send/post.rs +++ b/lemmy_apub/src/activities/send/post.rs @@ -5,8 +5,8 @@ use crate::{ ActorType, ApubLikeableType, ApubObjectType, - ToApub, }; +use crate::objects::ToApub; use activitystreams::{ activity::{ kind::{CreateType, DeleteType, DislikeType, LikeType, RemoveType, UndoType, UpdateType}, diff --git a/lemmy_apub/src/activities/send/private_message.rs b/lemmy_apub/src/activities/send/private_message.rs index 23528b5c7..602609c6b 100644 --- a/lemmy_apub/src/activities/send/private_message.rs +++ b/lemmy_apub/src/activities/send/private_message.rs @@ -4,8 +4,8 @@ use crate::{ extensions::context::lemmy_context, ActorType, ApubObjectType, - ToApub, }; +use crate::objects::ToApub; use activitystreams::{ activity::{ kind::{CreateType, DeleteType, UndoType, UpdateType}, diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index ec44bce17..afdab493f 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -1,7 +1,6 @@ use crate::{ check_is_apub_id_valid, ActorType, - FromApub, GroupExt, NoteExt, PageExt, @@ -39,6 +38,7 @@ use reqwest::Client; use serde::Deserialize; use std::{fmt::Debug, time::Duration}; use url::Url; +use crate::objects::FromApub; static ACTOR_REFETCH_INTERVAL_SECONDS: i64 = 24 * 60 * 60; static ACTOR_REFETCH_INTERVAL_SECONDS_DEBUG: i64 = 10; diff --git a/lemmy_apub/src/http/comment.rs b/lemmy_apub/src/http/comment.rs index 936cd9813..1792365f2 100644 --- a/lemmy_apub/src/http/comment.rs +++ b/lemmy_apub/src/http/comment.rs @@ -1,6 +1,5 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, - ToApub, }; use actix_web::{body::Body, web, web::Path, HttpResponse}; use diesel::result::Error::NotFound; @@ -9,6 +8,7 @@ use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; +use crate::objects::ToApub; #[derive(Deserialize)] pub struct CommentQuery { diff --git a/lemmy_apub/src/http/community.rs b/lemmy_apub/src/http/community.rs index 0e2f2802e..24d06c925 100644 --- a/lemmy_apub/src/http/community.rs +++ b/lemmy_apub/src/http/community.rs @@ -2,7 +2,6 @@ use crate::{ extensions::context::lemmy_context, http::{create_apub_response, create_apub_tombstone_response}, ActorType, - ToApub, }; use activitystreams::{ base::{AnyBase, BaseExt, ExtendsExt}, @@ -14,6 +13,7 @@ use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; +use crate::objects::ToApub; #[derive(Deserialize)] pub struct CommunityQuery { diff --git a/lemmy_apub/src/http/post.rs b/lemmy_apub/src/http/post.rs index 7f4bb447c..a38004129 100644 --- a/lemmy_apub/src/http/post.rs +++ b/lemmy_apub/src/http/post.rs @@ -1,6 +1,5 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, - ToApub, }; use actix_web::{body::Body, web, HttpResponse}; use diesel::result::Error::NotFound; @@ -9,6 +8,7 @@ use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; +use crate::objects::ToApub; #[derive(Deserialize)] pub struct PostQuery { diff --git a/lemmy_apub/src/http/user.rs b/lemmy_apub/src/http/user.rs index 0f2e1a71c..3c0e4789b 100644 --- a/lemmy_apub/src/http/user.rs +++ b/lemmy_apub/src/http/user.rs @@ -1,8 +1,9 @@ -use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType, ToApub}; +use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType}; use activitystreams::{ base::BaseExt, collection::{CollectionExt, OrderedCollection}, }; +use crate::objects::ToApub; use actix_web::{body::Body, web, HttpResponse}; use lemmy_db::user::User_; use lemmy_structs::blocking; diff --git a/lemmy_apub/src/lib.rs b/lemmy_apub/src/lib.rs index 45dbe8233..9b933b6e0 100644 --- a/lemmy_apub/src/lib.rs +++ b/lemmy_apub/src/lib.rs @@ -18,7 +18,7 @@ use activitystreams::{ activity::Follow, actor::{ApActor, Group, Person}, base::AnyBase, - object::{ApObject, Note, Page, Tombstone}, + object::{ApObject, Note, Page}, }; use activitystreams_ext::{Ext1, Ext2}; use anyhow::{anyhow, Context}; @@ -109,33 +109,6 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { } } -/// Trait for converting an object or actor into the respective ActivityPub type. -#[async_trait::async_trait(?Send)] -pub(crate) trait ToApub { - type ApubType; - async fn to_apub(&self, pool: &DbPool) -> Result; - fn to_tombstone(&self) -> Result; -} - -#[async_trait::async_trait(?Send)] -pub(crate) trait FromApub { - type ApubType; - /// Converts an object from ActivityPub type to Lemmy internal type. - /// - /// * `apub` The object to read from - /// * `context` LemmyContext which holds DB pool, HTTP client etc - /// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are - /// identical - async fn from_apub( - apub: &Self::ApubType, - context: &LemmyContext, - expected_domain: Option, - request_counter: &mut i32, - ) -> Result - where - Self: Sized; -} - /// Common functions for ActivityPub objects, which are implemented by most (but not all) objects /// and actors in Lemmy. #[async_trait::async_trait(?Send)] diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 277a55d06..5b9e2ca8d 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -11,9 +11,7 @@ use crate::{ get_source_markdown_value, set_content_and_source, }, - FromApub, NoteExt, - ToApub, }; use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, @@ -36,6 +34,8 @@ use lemmy_utils::{ }; use lemmy_websocket::LemmyContext; use url::Url; +use crate::objects::{FromApub, ToApub, FromApubToForm}; +use lemmy_utils::settings::Settings; #[async_trait::async_trait(?Send)] impl ToApub for Comment { @@ -87,12 +87,41 @@ impl ToApub for Comment { } #[async_trait::async_trait(?Send)] -impl FromApub for CommentForm { +impl FromApub for Comment { type ApubType = NoteExt; - /// Converts a `Note` to `CommentForm`. + /// Converts a `Note` to `Comment`. /// /// If the parent community, post and comment(s) are not known locally, these are also fetched. + async fn from_apub( + note: &NoteExt, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result { + let comment_id = note.id_unchecked().context(location_info!())?; + let domain = comment_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let comment = blocking(context.pool(), move |conn| { + Comment::read_from_apub_id(conn, comment_id.as_str()) + }) + .await??; + Ok(comment) + } else { + let comment_form = CommentForm::from_apub(note, context, expected_domain, request_counter)?; + let comment = blocking(context.pool(), move |conn| { + Comment::upsert(conn, comment_form) + }) + .await??; + Ok(comment) + } + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for CommentForm { + type ApubType = NoteExt; + async fn from_apub( note: &NoteExt, context: &LemmyContext, diff --git a/lemmy_apub/src/objects/community.rs b/lemmy_apub/src/objects/community.rs index 2b383ba5b..f91776fe8 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -8,9 +8,7 @@ use crate::{ set_content_and_source, }, ActorType, - FromApub, GroupExt, - ToApub, }; use activitystreams::{ actor::{kind::GroupType, ApActor, Endpoints, Group}, @@ -32,6 +30,7 @@ use lemmy_utils::{ utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; +use crate::objects::{FromApub, ToApub, FromApubToForm}; use lemmy_websocket::LemmyContext; use url::Url; @@ -106,8 +105,24 @@ impl ToApub for Community { create_tombstone(self.deleted, &self.actor_id, self.updated, GroupType::Group) } } + #[async_trait::async_trait(?Send)] -impl FromApub for CommunityForm { +impl FromApub for Community { + type ApubType = GroupExt; + + /// Converts a `Group` to `Community`. + async fn from_apub( + group: &GroupExt, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result { + todo!() + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for CommunityForm { type ApubType = GroupExt; async fn from_apub( diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index a162c165b..0d01102a0 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -9,6 +9,8 @@ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; use url::Url; +use lemmy_websocket::LemmyContext; +use lemmy_db::DbPool; pub(crate) mod comment; pub(crate) mod community; @@ -16,6 +18,46 @@ pub(crate) mod post; pub(crate) mod private_message; pub(crate) mod user; +/// Trait for converting an object or actor into the respective ActivityPub type. +#[async_trait::async_trait(?Send)] +pub(crate) trait ToApub { + type ApubType; + async fn to_apub(&self, pool: &DbPool) -> Result; + fn to_tombstone(&self) -> Result; +} + +#[async_trait::async_trait(?Send)] +pub(crate) trait FromApub { + type ApubType; + /// Converts an object from ActivityPub type to Lemmy internal type. + /// + /// * `apub` The object to read from + /// * `context` LemmyContext which holds DB pool, HTTP client etc + /// * `expected_domain` If present, ensure that the domains of this and of the apub object ID are + /// identical + async fn from_apub( + apub: &Self::ApubType, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result + where + Self: Sized; +} + +#[async_trait::async_trait(?Send)] +pub(in crate::objects) trait FromApubToForm { + type ApubType; + async fn from_apub( + apub: &Self::ApubType, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result + where + Self: Sized; +} + /// Updated is actually the deletion time fn create_tombstone( deleted: bool, diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index a058d8b7c..9bf15b2a9 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -7,9 +7,7 @@ use crate::{ get_source_markdown_value, set_content_and_source, }, - FromApub, PageExt, - ToApub, }; use activitystreams::{ object::{kind::PageType, ApObject, Image, Page, Tombstone}, @@ -35,6 +33,7 @@ use lemmy_utils::{ use lemmy_websocket::LemmyContext; use log::error; use url::Url; +use crate::objects::{FromApubToForm, ToApub, FromApub}; #[async_trait::async_trait(?Send)] impl ToApub for Post { @@ -98,12 +97,26 @@ impl ToApub for Post { } #[async_trait::async_trait(?Send)] -impl FromApub for PostForm { +impl FromApub for Post { type ApubType = PageExt; /// Converts a `PageExt` to `PostForm`. /// /// If the post's community or creator are not known locally, these are also fetched. + async fn from_apub( + note: &PageExt, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result { + todo!() + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for PostForm { + type ApubType = PageExt; + async fn from_apub( page: &PageExt, context: &LemmyContext, diff --git a/lemmy_apub/src/objects/private_message.rs b/lemmy_apub/src/objects/private_message.rs index 4e9af0943..659ea4059 100644 --- a/lemmy_apub/src/objects/private_message.rs +++ b/lemmy_apub/src/objects/private_message.rs @@ -8,10 +8,9 @@ use crate::{ get_source_markdown_value, set_content_and_source, }, - FromApub, NoteExt, - ToApub, }; +use crate::objects::{FromApubToForm, ToApub, FromApub}; use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, prelude::*, @@ -63,7 +62,21 @@ impl ToApub for PrivateMessage { } #[async_trait::async_trait(?Send)] -impl FromApub for PrivateMessageForm { +impl FromApub for PrivateMessage { + type ApubType = NoteExt; + + async fn from_apub( + note: &NoteExt, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result { + todo!() + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for PrivateMessageForm { type ApubType = NoteExt; async fn from_apub( diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index ddf33656c..9e6c4ad02 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -2,10 +2,9 @@ use crate::{ extensions::context::lemmy_context, objects::{check_object_domain, get_source_markdown_value, set_content_and_source}, ActorType, - FromApub, PersonExt, - ToApub, }; +use crate::objects::{FromApubToForm, ToApub, FromApub}; use activitystreams::{ actor::{ApActor, Endpoints, Person}, object::{ApObject, Image, Tombstone}, @@ -81,7 +80,21 @@ impl ToApub for User_ { } #[async_trait::async_trait(?Send)] -impl FromApub for UserForm { +impl FromApub for User_ { + type ApubType = PersonExt; + + async fn from_apub( + note: &PersonExt, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, + ) -> Result { + todo!() + } +} + +#[async_trait::async_trait(?Send)] +impl FromApubToForm for UserForm { type ApubType = PersonExt; async fn from_apub(