From 2bdb15b06dcd81c03e8fc4e137361949762afa92 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 12:19:24 +0100 Subject: [PATCH 01/15] Limit visibility of some traits and methods --- lemmy_apub/src/activity_queue.rs | 8 ++++---- lemmy_apub/src/extensions/signatures.rs | 5 ++++- lemmy_apub/src/lib.rs | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lemmy_apub/src/activity_queue.rs b/lemmy_apub/src/activity_queue.rs index 5e4f113b..46780279 100644 --- a/lemmy_apub/src/activity_queue.rs +++ b/lemmy_apub/src/activity_queue.rs @@ -33,7 +33,7 @@ use url::Url; /// * `activity` the apub activity to be sent /// * `creator` the local actor which created the activity /// * `inbox` the inbox url where the activity should be delivered to -pub async fn send_activity_single_dest( +pub(crate) async fn send_activity_single_dest( activity: T, creator: &dyn ActorType, inbox: Url, @@ -71,7 +71,7 @@ where /// * `community` the sending community /// * `sender_shared_inbox` in case of an announce, this should be the shared inbox of the inner /// activities creator, as receiving a known activity will cause an error -pub async fn send_to_community_followers( +pub(crate) async fn send_to_community_followers( activity: T, community: &Community, context: &LemmyContext, @@ -116,7 +116,7 @@ where /// * `creator` the creator of the activity /// * `community` the destination community /// -pub async fn send_to_community( +pub(crate) async fn send_to_community( activity: T, creator: &User_, community: &Community, @@ -160,7 +160,7 @@ where /// * `creator` user who created the comment /// * `mentions` list of inboxes of users which are mentioned in the comment /// * `activity` either a `Create/Note` or `Update/Note` -pub async fn send_comment_mentions( +pub(crate) async fn send_comment_mentions( creator: &User_, mentions: Vec, activity: T, diff --git a/lemmy_apub/src/extensions/signatures.rs b/lemmy_apub/src/extensions/signatures.rs index 6ff61df4..67fe4b1c 100644 --- a/lemmy_apub/src/extensions/signatures.rs +++ b/lemmy_apub/src/extensions/signatures.rs @@ -65,7 +65,10 @@ pub async fn sign_and_send( } /// Verifies the HTTP signature on an incoming inbox request. -pub fn verify_signature(request: &HttpRequest, actor: &dyn ActorType) -> Result<(), LemmyError> { +pub(crate) fn verify_signature( + request: &HttpRequest, + actor: &dyn ActorType, +) -> Result<(), LemmyError> { let public_key = actor.public_key().context(location_info!())?; let verified = CONFIG2 .begin_verify( diff --git a/lemmy_apub/src/lib.rs b/lemmy_apub/src/lib.rs index 2e3f7bfc..45dbe823 100644 --- a/lemmy_apub/src/lib.rs +++ b/lemmy_apub/src/lib.rs @@ -111,14 +111,14 @@ 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 trait ToApub { +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 trait FromApub { +pub(crate) trait FromApub { type ApubType; /// Converts an object from ActivityPub type to Lemmy internal type. /// @@ -248,7 +248,7 @@ pub trait ActorType { /// Store a sent or received activity in the database, for logging purposes. These records are not /// persistent. -pub async fn insert_activity( +pub(crate) async fn insert_activity( ap_id: &Url, activity: T, local: bool, -- 2.40.1 From 9cbb80ca8ee62e3ff545ddaa8adb98d4682791e6 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 13:00:18 +0100 Subject: [PATCH 02/15] WIP: alternative way to handle non-local object parsing --- lemmy_apub/src/activities/receive/comment.rs | 2 +- .../src/activities/receive/comment_undo.rs | 2 +- lemmy_apub/src/activities/receive/post.rs | 2 +- .../src/activities/receive/post_undo.rs | 2 +- .../src/activities/receive/private_message.rs | 2 +- lemmy_apub/src/activities/send/comment.rs | 2 +- lemmy_apub/src/activities/send/post.rs | 2 +- .../src/activities/send/private_message.rs | 2 +- lemmy_apub/src/fetcher.rs | 2 +- lemmy_apub/src/http/comment.rs | 2 +- lemmy_apub/src/http/community.rs | 2 +- lemmy_apub/src/http/post.rs | 2 +- lemmy_apub/src/http/user.rs | 3 +- lemmy_apub/src/lib.rs | 29 +------------ lemmy_apub/src/objects/comment.rs | 37 ++++++++++++++-- lemmy_apub/src/objects/community.rs | 21 ++++++++-- lemmy_apub/src/objects/mod.rs | 42 +++++++++++++++++++ lemmy_apub/src/objects/post.rs | 19 +++++++-- lemmy_apub/src/objects/private_message.rs | 19 +++++++-- lemmy_apub/src/objects/user.rs | 19 +++++++-- 20 files changed, 156 insertions(+), 57 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index bf8de1eb..89baf997 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 f44604cc..b859e1c5 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 80044237..785a3a1e 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 99d0ed1d..12ed266f 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 8f1c95b9..a954d62d 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 2aee7b6e..856ad8fc 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 da78667f..9e42a269 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 23528b5c..602609c6 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 ec44bce1..afdab493 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 936cd981..1792365f 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 0e2f2802..24d06c92 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 7f4bb447..a3800412 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 0f2e1a71..3c0e4789 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 45dbe823..9b933b6e 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 277a55d0..5b9e2ca8 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 2b383ba5..f91776fe 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 a162c165..0d01102a 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 a058d8b7..9bf15b2a 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 4e9af094..659ea405 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 ddf33656..9e6c4ad0 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( -- 2.40.1 From dbf9c697098065afd2476e126080113dcb07fdd1 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 17:10:58 +0100 Subject: [PATCH 03/15] finish this --- lemmy_apub/src/activities/receive/comment.rs | 74 +++++++------------ .../src/activities/receive/comment_undo.rs | 25 ++++--- lemmy_apub/src/activities/receive/post.rs | 40 +++++----- .../src/activities/receive/post_undo.rs | 15 ++-- .../src/activities/receive/private_message.rs | 37 ++-------- lemmy_apub/src/activities/send/comment.rs | 2 +- lemmy_apub/src/activities/send/post.rs | 2 +- .../src/activities/send/private_message.rs | 2 +- lemmy_apub/src/fetcher.rs | 64 +++++----------- lemmy_apub/src/http/comment.rs | 2 +- lemmy_apub/src/http/community.rs | 2 +- lemmy_apub/src/http/post.rs | 2 +- lemmy_apub/src/http/user.rs | 8 +- lemmy_apub/src/objects/comment.rs | 19 +++-- lemmy_apub/src/objects/community.rs | 23 +++++- lemmy_apub/src/objects/mod.rs | 14 ++-- lemmy_apub/src/objects/post.rs | 21 +++++- lemmy_apub/src/objects/private_message.rs | 24 +++++- lemmy_apub/src/objects/user.rs | 29 +++++++- 19 files changed, 210 insertions(+), 195 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index 89baf997..26220d06 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -1,6 +1,7 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_comment, + objects::FromApub, ActorType, NoteExt, }; @@ -10,16 +11,15 @@ use activitystreams::{ }; use anyhow::{anyhow, Context}; use lemmy_db::{ - comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, + comment::{Comment, CommentLike, CommentLikeForm}, comment_view::CommentView, post::Post, - Crud, Likeable, }; 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; +use url::Url; pub(crate) async fn receive_create_comment( create: Create, @@ -30,8 +30,8 @@ pub(crate) async fn receive_create_comment( let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let comment = - CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + // TODO: need to do the check for locked post before calling this + let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -39,27 +39,17 @@ pub(crate) async fn receive_create_comment( return Err(anyhow!("Post is locked").into()); } - let inserted_comment = - blocking(context.pool(), move |conn| Comment::upsert(conn, &comment)).await??; - // Note: // Although mentions could be gotten from the post tags (they are included there), or the ccs, // Its much easier to scrape them from the comment body, since the API has to do that // anyway. - let mentions = scrape_text_for_mentions(&inserted_comment.content); - let recipient_ids = send_local_notifs( - mentions, - inserted_comment.clone(), - &user, - post, - context.pool(), - true, - ) - .await?; + let mentions = scrape_text_for_mentions(&comment.content); + let recipient_ids = + send_local_notifs(mentions, comment.clone(), &user, post, context.pool(), true).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, inserted_comment.id, None) + CommentView::read(conn, comment.id, None) }) .await??; @@ -87,32 +77,20 @@ pub(crate) async fn receive_update_comment( .context(location_info!())?; let user = get_actor_as_user(&update, context, request_counter).await?; - let comment = - CommentForm::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + // TODO: why fetch? let original_comment_id = - get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) + get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) .await? .id; - let updated_comment = blocking(context.pool(), move |conn| { - Comment::update(conn, original_comment_id, &comment) - }) - .await??; - - let post_id = updated_comment.post_id; + let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - let mentions = scrape_text_for_mentions(&updated_comment.content); - let recipient_ids = send_local_notifs( - mentions, - updated_comment, - &user, - post, - context.pool(), - false, - ) - .await?; + let mentions = scrape_text_for_mentions(&comment.content); + let recipient_ids = + send_local_notifs(mentions, comment, &user, post, context.pool(), false).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { @@ -144,11 +122,13 @@ pub(crate) async fn receive_like_comment( .context(location_info!())?; let user = get_actor_as_user(&like, context, request_counter).await?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; + let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + // TODO: why do we need to fetch here if we already have the comment? + let comment_id = + get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) + .await? + .id; let like_form = CommentLikeForm { comment_id, @@ -201,11 +181,13 @@ pub(crate) async fn receive_dislike_comment( .context(location_info!())?; let user = get_actor_as_user(&dislike, context, request_counter).await?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; + let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + // TODO: same as above, why fetch here? + let comment_id = + get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) + .await? + .id; let like_form = CommentLikeForm { comment_id, diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index b859e1c5..5e5295d7 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,19 +1,20 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_comment, + objects::FromApub, NoteExt, }; -use crate::objects::FromApub; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ - comment::{Comment, CommentForm, CommentLike}, + comment::{Comment, CommentLike}, comment_view::CommentView, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; +use url::Url; pub(crate) async fn receive_undo_like_comment( like: &Like, @@ -24,11 +25,13 @@ pub(crate) async fn receive_undo_like_comment( let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; + let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + // TODO: why? + let comment_id = + get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) + .await? + .id; let user_id = user.id; blocking(context.pool(), move |conn| { @@ -74,11 +77,13 @@ pub(crate) async fn receive_undo_dislike_comment( )? .context(location_info!())?; - let comment = CommentForm::from_apub(¬e, context, None, request_counter).await?; + let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - let comment_id = get_or_fetch_and_insert_comment(&comment.get_ap_id()?, context, request_counter) - .await? - .id; + // TODO + let comment_id = + get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) + .await? + .id; let user_id = user.id; blocking(context.pool(), move |conn| { diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index 785a3a1e..e8f4b61b 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -1,24 +1,24 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_post, + objects::FromApub, ActorType, PageExt, }; -use crate::objects::FromApub; use activitystreams::{ activity::{Create, Dislike, Like, Remove, Update}, prelude::*, }; use anyhow::Context; use lemmy_db::{ - post::{Post, PostForm, PostLike, PostLikeForm}, + post::{Post, PostLike, PostLikeForm}, post_view::PostView, - Crud, Likeable, }; use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; +use url::Url; pub(crate) async fn receive_create_post( create: Create, @@ -29,16 +29,12 @@ pub(crate) async fn receive_create_post( let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; - - // Using an upsert, since likes (which fetch the post), sometimes come in before the create - // resulting in double posts. - let inserted_post = blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??; + let post = Post::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; // Refetch the view - let inserted_post_id = inserted_post.id; + let post_id = post.id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, inserted_post_id, None) + PostView::read(conn, post_id, None) }) .await??; @@ -62,16 +58,13 @@ pub(crate) async fn receive_update_post( let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; + let post = Post::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; - let original_post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) - .await? - .id; - - blocking(context.pool(), move |conn| { - Post::update(conn, original_post_id, &post) - }) - .await??; + // TODO: why? + let original_post_id = + get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) + .await? + .id; // Refetch the view let post_view = blocking(context.pool(), move |conn| { @@ -99,9 +92,10 @@ pub(crate) async fn receive_like_post( let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, None, request_counter).await?; + let post = Post::from_apub(&page, context, None, request_counter).await?; - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) + // TODO: why? + let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) .await? .id; @@ -149,9 +143,9 @@ pub(crate) async fn receive_dislike_post( )? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, None, request_counter).await?; + let post = Post::from_apub(&page, context, None, request_counter).await?; - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) + let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) .await? .id; diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index 12ed266f..8d45f7fa 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,19 +1,20 @@ use crate::{ activities::receive::get_actor_as_user, fetcher::get_or_fetch_and_insert_post, + objects::FromApub, PageExt, }; -use crate::objects::FromApub; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ - post::{Post, PostForm, PostLike}, + post::{Post, PostLike}, post_view::PostView, Likeable, }; use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; +use url::Url; pub(crate) async fn receive_undo_like_post( like: &Like, @@ -24,9 +25,10 @@ pub(crate) async fn receive_undo_like_post( let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, None, request_counter).await?; + let post = Post::from_apub(&page, context, None, request_counter).await?; - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) + // TODO: why? + let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) .await? .id; @@ -68,9 +70,10 @@ pub(crate) async fn receive_undo_dislike_post( )? .context(location_info!())?; - let post = PostForm::from_apub(&page, context, None, request_counter).await?; + let post = Post::from_apub(&page, context, None, request_counter).await?; - let post_id = get_or_fetch_and_insert_post(&post.get_ap_id()?, context, request_counter) + // TODO: why? + let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) .await? .id; diff --git a/lemmy_apub/src/activities/receive/private_message.rs b/lemmy_apub/src/activities/receive/private_message.rs index a954d62d..74ce004a 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, + objects::FromApub, NoteExt, }; -use crate::objects::FromApub; use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Delete, Undo, Update}, base::{AsBase, ExtendsExt}, @@ -13,11 +13,7 @@ use activitystreams::{ public, }; use anyhow::{anyhow, Context}; -use lemmy_db::{ - private_message::{PrivateMessage, PrivateMessageForm}, - private_message_view::PrivateMessageView, - Crud, -}; +use lemmy_db::{private_message::PrivateMessage, private_message_view::PrivateMessageView}; use lemmy_structs::{blocking, user::PrivateMessageResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation}; @@ -41,15 +37,10 @@ pub(crate) async fn receive_create_private_message( .context(location_info!())?; let private_message = - PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?; - - let inserted_private_message = blocking(&context.pool(), move |conn| { - PrivateMessage::create(conn, &private_message) - }) - .await??; + PrivateMessage::from_apub(¬e, context, Some(expected_domain), request_counter).await?; let message = blocking(&context.pool(), move |conn| { - PrivateMessageView::read(conn, inserted_private_message.id) + PrivateMessageView::read(conn, private_message.id) }) .await??; @@ -82,24 +73,8 @@ pub(crate) async fn receive_update_private_message( .to_owned(); let note = NoteExt::from_any_base(object)?.context(location_info!())?; - let private_message_form = - PrivateMessageForm::from_apub(¬e, context, Some(expected_domain), request_counter).await?; - - let private_message_ap_id = private_message_form - .ap_id - .as_ref() - .context(location_info!())? - .clone(); - let private_message = blocking(&context.pool(), move |conn| { - PrivateMessage::read_from_apub_id(conn, &private_message_ap_id) - }) - .await??; - - let private_message_id = private_message.id; - blocking(&context.pool(), move |conn| { - PrivateMessage::update(conn, private_message_id, &private_message_form) - }) - .await??; + let private_message = + PrivateMessage::from_apub(¬e, context, Some(expected_domain), request_counter).await?; let private_message_id = private_message.id; let message = blocking(&context.pool(), move |conn| { diff --git a/lemmy_apub/src/activities/send/comment.rs b/lemmy_apub/src/activities/send/comment.rs index 856ad8fc..4415211f 100644 --- a/lemmy_apub/src/activities/send/comment.rs +++ b/lemmy_apub/src/activities/send/comment.rs @@ -3,6 +3,7 @@ use crate::{ activity_queue::{send_comment_mentions, send_to_community}, extensions::context::lemmy_context, fetcher::get_or_fetch_and_upsert_user, + objects::ToApub, ActorType, ApubLikeableType, ApubObjectType, @@ -38,7 +39,6 @@ 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 9e42a269..d5ff56ac 100644 --- a/lemmy_apub/src/activities/send/post.rs +++ b/lemmy_apub/src/activities/send/post.rs @@ -2,11 +2,11 @@ use crate::{ activities::send::generate_activity_id, activity_queue::send_to_community, extensions::context::lemmy_context, + objects::ToApub, ActorType, ApubLikeableType, ApubObjectType, }; -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 602609c6..e8bc979a 100644 --- a/lemmy_apub/src/activities/send/private_message.rs +++ b/lemmy_apub/src/activities/send/private_message.rs @@ -2,10 +2,10 @@ use crate::{ activities::send::generate_activity_id, activity_queue::send_activity_single_dest, extensions::context::lemmy_context, + objects::ToApub, ActorType, ApubObjectType, }; -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 afdab493..76d8b645 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -1,5 +1,6 @@ use crate::{ check_is_apub_id_valid, + objects::FromApub, ActorType, GroupExt, NoteExt, @@ -12,16 +13,15 @@ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use diesel::result::Error::NotFound; use lemmy_db::{ - comment::{Comment, CommentForm}, + comment::Comment, comment_view::CommentView, - community::{Community, CommunityForm, CommunityModerator, CommunityModeratorForm}, + community::{Community, CommunityModerator, CommunityModeratorForm}, community_view::CommunityView, naive_now, - post::{Post, PostForm}, + post::Post, post_view::PostView, - user::{UserForm, User_}, + user::User_, user_view::UserView, - Crud, Joinable, SearchType, }; @@ -38,7 +38,6 @@ 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; @@ -184,22 +183,16 @@ pub async fn search_by_apub_id( response } SearchAcceptedObjects::Page(p) => { - let post_form = PostForm::from_apub(&p, context, Some(query_url), recursion_counter).await?; + let p = Post::from_apub(&p, context, Some(query_url), recursion_counter).await?; - let p = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; response.posts = vec![blocking(context.pool(), move |conn| PostView::read(conn, p.id, None)).await??]; response } SearchAcceptedObjects::Comment(c) => { - let comment_form = - CommentForm::from_apub(&c, context, Some(query_url), recursion_counter).await?; + let c = Comment::from_apub(&c, context, Some(query_url), recursion_counter).await?; - let c = blocking(context.pool(), move |conn| { - Comment::upsert(conn, &comment_form) - }) - .await??; response.comments = vec![ blocking(context.pool(), move |conn| { CommentView::read(conn, c.id, None) @@ -258,15 +251,15 @@ pub(crate) async fn get_or_fetch_and_upsert_user( return Ok(u); } - let mut uf = UserForm::from_apub( + let user = User_::from_apub( &person?, context, Some(apub_id.to_owned()), recursion_counter, ) .await?; - uf.last_refreshed_at = Some(naive_now()); - let user = blocking(context.pool(), move |conn| User_::update(conn, u.id, &uf)).await??; + // TODO: do we need to set this? would need a separate db call + //uf.last_refreshed_at = Some(naive_now()); Ok(user) } @@ -276,14 +269,13 @@ pub(crate) async fn get_or_fetch_and_upsert_user( let person = fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; - let uf = UserForm::from_apub( + let user = User_::from_apub( &person, context, Some(apub_id.to_owned()), recursion_counter, ) .await?; - let user = blocking(context.pool(), move |conn| User_::upsert(conn, &uf)).await??; Ok(user) } @@ -354,9 +346,8 @@ async fn fetch_remote_community( } let group = group?; - let cf = - CommunityForm::from_apub(&group, context, Some(apub_id.to_owned()), recursion_counter).await?; - let community = blocking(context.pool(), move |conn| Community::upsert(conn, &cf)).await??; + let community = + Community::from_apub(&group, context, Some(apub_id.to_owned()), recursion_counter).await?; // Also add the community moderators too let attributed_to = group.inner.attributed_to().context(location_info!())?; @@ -409,20 +400,10 @@ async fn fetch_remote_community( // The post creator may be from a blocked instance, // if it errors, then continue - let post = match PostForm::from_apub(&page, context, None, recursion_counter).await { + match Post::from_apub(&page, context, None, recursion_counter).await { Ok(post) => post, Err(_) => continue, }; - let post_ap_id = post.ap_id.as_ref().context(location_info!())?.clone(); - // Check whether the post already exists in the local db - let existing = blocking(context.pool(), move |conn| { - Post::read_from_apub_id(conn, &post_ap_id) - }) - .await?; - match existing { - Ok(e) => blocking(context.pool(), move |conn| Post::update(conn, e.id, &post)).await??, - Err(_) => blocking(context.pool(), move |conn| Post::upsert(conn, &post)).await??, - }; // TODO: we need to send a websocket update here } @@ -448,18 +429,16 @@ pub(crate) async fn get_or_fetch_and_insert_post( Ok(p) => Ok(p), Err(NotFound {}) => { debug!("Fetching and creating remote post: {}", post_ap_id); - let post = + let page = fetch_remote_object::(context.client(), post_ap_id, recursion_counter).await?; - let post_form = PostForm::from_apub( - &post, + let post = Post::from_apub( + &page, context, Some(post_ap_id.to_owned()), recursion_counter, ) .await?; - let post = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; - Ok(post) } Err(e) => Err(e.into()), @@ -490,7 +469,7 @@ pub(crate) async fn get_or_fetch_and_insert_comment( ); let comment = fetch_remote_object::(context.client(), comment_ap_id, recursion_counter).await?; - let comment_form = CommentForm::from_apub( + let comment = Comment::from_apub( &comment, context, Some(comment_ap_id.to_owned()), @@ -498,17 +477,12 @@ pub(crate) async fn get_or_fetch_and_insert_comment( ) .await?; - let post_id = comment_form.post_id; + let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; if post.locked { return Err(anyhow!("Post is locked").into()); } - let comment = blocking(context.pool(), move |conn| { - Comment::upsert(conn, &comment_form) - }) - .await??; - Ok(comment) } Err(e) => Err(e.into()), diff --git a/lemmy_apub/src/http/comment.rs b/lemmy_apub/src/http/comment.rs index 1792365f..bb3d13ac 100644 --- a/lemmy_apub/src/http/comment.rs +++ b/lemmy_apub/src/http/comment.rs @@ -1,5 +1,6 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, + objects::ToApub, }; use actix_web::{body::Body, web, web::Path, HttpResponse}; use diesel::result::Error::NotFound; @@ -8,7 +9,6 @@ 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 24d06c92..0a90571f 100644 --- a/lemmy_apub/src/http/community.rs +++ b/lemmy_apub/src/http/community.rs @@ -1,6 +1,7 @@ use crate::{ extensions::context::lemmy_context, http::{create_apub_response, create_apub_tombstone_response}, + objects::ToApub, ActorType, }; use activitystreams::{ @@ -13,7 +14,6 @@ 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 a3800412..1d25ed95 100644 --- a/lemmy_apub/src/http/post.rs +++ b/lemmy_apub/src/http/post.rs @@ -1,5 +1,6 @@ use crate::{ http::{create_apub_response, create_apub_tombstone_response}, + objects::ToApub, }; use actix_web::{body::Body, web, HttpResponse}; use diesel::result::Error::NotFound; @@ -8,7 +9,6 @@ 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 3c0e4789..1e546d95 100644 --- a/lemmy_apub/src/http/user.rs +++ b/lemmy_apub/src/http/user.rs @@ -1,9 +1,13 @@ -use crate::{extensions::context::lemmy_context, http::create_apub_response, ActorType}; +use crate::{ + extensions::context::lemmy_context, + http::create_apub_response, + objects::ToApub, + 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/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 5b9e2ca8..b92411e7 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -10,6 +10,9 @@ use crate::{ create_tombstone, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, NoteExt, }; @@ -29,13 +32,12 @@ use lemmy_db::{ use lemmy_structs::blocking; use lemmy_utils::{ location_info, + settings::Settings, utils::{convert_datetime, remove_slurs}, LemmyError, }; 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 { @@ -99,20 +101,23 @@ impl FromApub for Comment { expected_domain: Option, request_counter: &mut i32, ) -> Result { - let comment_id = note.id_unchecked().context(location_info!())?; + // TODO: we should move read_from_apub_id() and upsert() into traits so we can make a generic + // function to handle all this (shared with User_::from_apub etc) + let comment_id = note.id_unchecked().context(location_info!())?.to_owned(); 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??; + .await??; Ok(comment) } else { - let comment_form = CommentForm::from_apub(note, context, expected_domain, request_counter)?; + let comment_form = + CommentForm::from_apub(note, context, expected_domain, request_counter).await?; let comment = blocking(context.pool(), move |conn| { - Comment::upsert(conn, comment_form) + Comment::upsert(conn, &comment_form) }) - .await??; + .await??; Ok(comment) } } diff --git a/lemmy_apub/src/objects/community.rs b/lemmy_apub/src/objects/community.rs index f91776fe..57cc4737 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -6,6 +6,9 @@ use crate::{ create_tombstone, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, ActorType, GroupExt, @@ -27,10 +30,10 @@ use lemmy_db::{ use lemmy_structs::blocking; use lemmy_utils::{ location_info, + settings::Settings, utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; -use crate::objects::{FromApub, ToApub, FromApubToForm}; use lemmy_websocket::LemmyContext; use url::Url; @@ -117,7 +120,23 @@ impl FromApub for Community { expected_domain: Option, request_counter: &mut i32, ) -> Result { - todo!() + let community_id = group.id_unchecked().context(location_info!())?.to_owned(); + let domain = community_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let community = blocking(context.pool(), move |conn| { + Community::read_from_actor_id(conn, community_id.as_str()) + }) + .await??; + Ok(community) + } else { + let community_form = + CommunityForm::from_apub(group, context, expected_domain, request_counter).await?; + let community = blocking(context.pool(), move |conn| { + Community::upsert(conn, &community_form) + }) + .await??; + Ok(community) + } } } diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index 0d01102a..8258e746 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -7,10 +7,10 @@ use activitystreams::{ }; 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; +use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; +use lemmy_websocket::LemmyContext; +use url::Url; pub(crate) mod comment; pub(crate) mod community; @@ -41,8 +41,8 @@ pub(crate) trait FromApub { expected_domain: Option, request_counter: &mut i32, ) -> Result - where - Self: Sized; + where + Self: Sized; } #[async_trait::async_trait(?Send)] @@ -54,8 +54,8 @@ pub(in crate::objects) trait FromApubToForm { expected_domain: Option, request_counter: &mut i32, ) -> Result - where - Self: Sized; + where + Self: Sized; } /// Updated is actually the deletion time diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index 9bf15b2a..7151ee33 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -6,6 +6,9 @@ use crate::{ create_tombstone, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, PageExt, }; @@ -27,13 +30,13 @@ use lemmy_structs::blocking; use lemmy_utils::{ location_info, request::fetch_iframely_and_pictrs_data, + settings::Settings, utils::{check_slurs, convert_datetime, remove_slurs}, LemmyError, }; 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 { @@ -104,12 +107,24 @@ impl FromApub for Post { /// /// If the post's community or creator are not known locally, these are also fetched. async fn from_apub( - note: &PageExt, + page: &PageExt, context: &LemmyContext, expected_domain: Option, request_counter: &mut i32, ) -> Result { - todo!() + let post_id = page.id_unchecked().context(location_info!())?.to_owned(); + let domain = post_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let post = blocking(context.pool(), move |conn| { + Post::read_from_apub_id(conn, post_id.as_str()) + }) + .await??; + Ok(post) + } else { + let post_form = PostForm::from_apub(page, context, expected_domain, request_counter).await?; + let post = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; + Ok(post) + } } } diff --git a/lemmy_apub/src/objects/private_message.rs b/lemmy_apub/src/objects/private_message.rs index 659ea405..80bc4e66 100644 --- a/lemmy_apub/src/objects/private_message.rs +++ b/lemmy_apub/src/objects/private_message.rs @@ -7,10 +7,12 @@ use crate::{ create_tombstone, get_source_markdown_value, set_content_and_source, + FromApub, + FromApubToForm, + ToApub, }, NoteExt, }; -use crate::objects::{FromApubToForm, ToApub, FromApub}; use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, prelude::*, @@ -23,7 +25,7 @@ use lemmy_db::{ DbPool, }; use lemmy_structs::blocking; -use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; +use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -71,7 +73,23 @@ impl FromApub for PrivateMessage { expected_domain: Option, request_counter: &mut i32, ) -> Result { - todo!() + let private_message_id = note.id_unchecked().context(location_info!())?.to_owned(); + let domain = private_message_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let private_message = blocking(context.pool(), move |conn| { + PrivateMessage::read_from_apub_id(conn, private_message_id.as_str()) + }) + .await??; + Ok(private_message) + } else { + let private_message_form = + PrivateMessageForm::from_apub(note, context, expected_domain, request_counter).await?; + let private_message = blocking(context.pool(), move |conn| { + PrivateMessage::upsert(conn, &private_message_form) + }) + .await??; + Ok(private_message) + } } } diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index 9e6c4ad0..7162a117 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -1,10 +1,16 @@ use crate::{ extensions::context::lemmy_context, - objects::{check_object_domain, get_source_markdown_value, set_content_and_source}, + objects::{ + check_object_domain, + get_source_markdown_value, + set_content_and_source, + FromApub, + FromApubToForm, + ToApub, + }, ActorType, PersonExt, }; -use crate::objects::{FromApubToForm, ToApub, FromApub}; use activitystreams::{ actor::{ApActor, Endpoints, Person}, object::{ApObject, Image, Tombstone}, @@ -17,8 +23,10 @@ use lemmy_db::{ user::{UserForm, User_}, DbPool, }; +use lemmy_structs::blocking; use lemmy_utils::{ location_info, + settings::Settings, utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; @@ -84,12 +92,25 @@ impl FromApub for User_ { type ApubType = PersonExt; async fn from_apub( - note: &PersonExt, + person: &PersonExt, context: &LemmyContext, expected_domain: Option, request_counter: &mut i32, ) -> Result { - todo!() + let user_id = person.id_unchecked().context(location_info!())?.to_owned(); + let domain = user_id.domain().context(location_info!())?; + if domain == Settings::get().hostname { + let user = blocking(context.pool(), move |conn| { + User_::read_from_actor_id(conn, user_id.as_str()) + }) + .await??; + Ok(user) + } else { + let user_form = + UserForm::from_apub(person, context, expected_domain, request_counter).await?; + let user = blocking(context.pool(), move |conn| User_::upsert(conn, &user_form)).await??; + Ok(user) + } } } -- 2.40.1 From 9629f8140b3c58bb97db3cb6f5ea9a9781bc424e Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 17:34:14 +0100 Subject: [PATCH 04/15] cleanup --- lemmy_apub/src/activities/receive/comment.rs | 32 +++---------------- .../src/activities/receive/comment_undo.rs | 22 ++----------- lemmy_apub/src/activities/receive/post.rs | 29 +++-------------- .../src/activities/receive/post_undo.rs | 20 ++---------- 4 files changed, 16 insertions(+), 87 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index 26220d06..6f6a22da 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -1,10 +1,4 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_comment, - objects::FromApub, - ActorType, - NoteExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt}; use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, base::ExtendsExt, @@ -19,7 +13,6 @@ 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 url::Url; pub(crate) async fn receive_create_comment( create: Create, @@ -79,12 +72,7 @@ pub(crate) async fn receive_update_comment( let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; - // TODO: why fetch? - let original_comment_id = - get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -94,7 +82,7 @@ pub(crate) async fn receive_update_comment( // Refetch the view let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, original_comment_id, None) + CommentView::read(conn, comment_id, None) }) .await??; @@ -124,12 +112,7 @@ pub(crate) async fn receive_like_comment( let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - // TODO: why do we need to fetch here if we already have the comment? - let comment_id = - get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, @@ -183,12 +166,7 @@ pub(crate) async fn receive_dislike_comment( let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - // TODO: same as above, why fetch here? - let comment_id = - get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index 5e5295d7..2ccec087 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,9 +1,4 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_comment, - objects::FromApub, - NoteExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, NoteExt}; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ @@ -14,7 +9,6 @@ use lemmy_db::{ use lemmy_structs::{blocking, comment::CommentResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; -use url::Url; pub(crate) async fn receive_undo_like_comment( like: &Like, @@ -27,12 +21,7 @@ pub(crate) async fn receive_undo_like_comment( let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - // TODO: why? - let comment_id = - get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let user_id = user.id; blocking(context.pool(), move |conn| { CommentLike::remove(conn, user_id, comment_id) @@ -79,12 +68,7 @@ pub(crate) async fn receive_undo_dislike_comment( let comment = Comment::from_apub(¬e, context, None, request_counter).await?; - // TODO - let comment_id = - get_or_fetch_and_insert_comment(&Url::parse(&comment.ap_id)?, context, request_counter) - .await? - .id; - + let comment_id = comment.id; let user_id = user.id; blocking(context.pool(), move |conn| { CommentLike::remove(conn, user_id, comment_id) diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index e8f4b61b..d1c92157 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -1,10 +1,4 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_post, - objects::FromApub, - ActorType, - PageExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt}; use activitystreams::{ activity::{Create, Dislike, Like, Remove, Update}, prelude::*, @@ -18,7 +12,6 @@ use lemmy_db::{ use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; -use url::Url; pub(crate) async fn receive_create_post( create: Create, @@ -60,15 +53,10 @@ pub(crate) async fn receive_update_post( let post = Post::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; - // TODO: why? - let original_post_id = - get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) - .await? - .id; - + let post_id = post.id; // Refetch the view let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, original_post_id, None) + PostView::read(conn, post_id, None) }) .await??; @@ -94,11 +82,7 @@ pub(crate) async fn receive_like_post( let post = Post::from_apub(&page, context, None, request_counter).await?; - // TODO: why? - let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) - .await? - .id; - + let post_id = post.id; let like_form = PostLikeForm { post_id, user_id: user.id, @@ -145,10 +129,7 @@ pub(crate) async fn receive_dislike_post( let post = Post::from_apub(&page, context, None, request_counter).await?; - let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) - .await? - .id; - + let post_id = post.id; let like_form = PostLikeForm { post_id, user_id: user.id, diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index 8d45f7fa..aced5f4b 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,9 +1,4 @@ -use crate::{ - activities::receive::get_actor_as_user, - fetcher::get_or_fetch_and_insert_post, - objects::FromApub, - PageExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, PageExt}; use activitystreams::{activity::*, prelude::*}; use anyhow::Context; use lemmy_db::{ @@ -14,7 +9,6 @@ use lemmy_db::{ use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; -use url::Url; pub(crate) async fn receive_undo_like_post( like: &Like, @@ -27,11 +21,7 @@ pub(crate) async fn receive_undo_like_post( let post = Post::from_apub(&page, context, None, request_counter).await?; - // TODO: why? - let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) - .await? - .id; - + let post_id = post.id; let user_id = user.id; blocking(context.pool(), move |conn| { PostLike::remove(conn, user_id, post_id) @@ -72,11 +62,7 @@ pub(crate) async fn receive_undo_dislike_post( let post = Post::from_apub(&page, context, None, request_counter).await?; - // TODO: why? - let post_id = get_or_fetch_and_insert_post(&Url::parse(&post.ap_id)?, context, request_counter) - .await? - .id; - + let post_id = post.id; let user_id = user.id; blocking(context.pool(), move |conn| { PostLike::remove(conn, user_id, post_id) -- 2.40.1 From 6cf4e39406b3bce863ec114a7a2355d204facd23 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 17:41:01 +0100 Subject: [PATCH 05/15] Move check for locked post into Comment::from_apub() --- lemmy_apub/src/activities/receive/comment.rs | 6 +----- lemmy_apub/src/objects/comment.rs | 8 +++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index 6f6a22da..da29a3b7 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -3,7 +3,7 @@ use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, base::ExtendsExt, }; -use anyhow::{anyhow, Context}; +use anyhow::Context; use lemmy_db::{ comment::{Comment, CommentLike, CommentLikeForm}, comment_view::CommentView, @@ -23,14 +23,10 @@ pub(crate) async fn receive_create_comment( let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - // TODO: need to do the check for locked post before calling this let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - if post.locked { - return Err(anyhow!("Post is locked").into()); - } // Note: // Although mentions could be gotten from the post tags (they are included there), or the ccs, diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index b92411e7..1454a738 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -20,7 +20,7 @@ use activitystreams::{ object::{kind::NoteType, ApObject, Note, Tombstone}, prelude::*, }; -use anyhow::Context; +use anyhow::{anyhow, Context}; use lemmy_db::{ comment::{Comment, CommentForm}, community::Community, @@ -114,6 +114,12 @@ impl FromApub for Comment { } else { let comment_form = CommentForm::from_apub(note, context, expected_domain, request_counter).await?; + let post_id = comment_form.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + if post.locked { + return Err(anyhow!("Post is locked").into()); + } + let comment = blocking(context.pool(), move |conn| { Comment::upsert(conn, &comment_form) }) -- 2.40.1 From 89f9ecb634de7f8d8e19fabf39111a19fbc81daa Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 18:45:46 +0100 Subject: [PATCH 06/15] Mark user as updated after fetching --- lemmy_apub/src/fetcher.rs | 8 ++++++-- lemmy_db/src/user.rs | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index 76d8b645..0fb0cb10 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -258,8 +258,12 @@ pub(crate) async fn get_or_fetch_and_upsert_user( recursion_counter, ) .await?; - // TODO: do we need to set this? would need a separate db call - //uf.last_refreshed_at = Some(naive_now()); + + let user_id = user.id; + blocking(context.pool(), move |conn| { + User_::mark_as_updated(conn, user_id) + }) + .await??; Ok(user) } diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index 2c4c67ea..3f2efd2c 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -188,6 +188,12 @@ impl User_ { .get_result::(conn) } + pub fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result { + diesel::update(user_.find(user_id)) + .set((updated.eq(naive_now()),)) + .get_result::(conn) + } + pub fn delete_account(conn: &PgConnection, user_id: i32) -> Result { diesel::update(user_.find(user_id)) .set(( -- 2.40.1 From c5f08768cddc7324bbbb4afacf90b444bec027b0 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 1 Dec 2020 21:07:32 +0100 Subject: [PATCH 07/15] Should set last_refreshed_at, not updated --- lemmy_db/src/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index 3f2efd2c..4733fdfe 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -190,7 +190,7 @@ impl User_ { pub fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result { diesel::update(user_.find(user_id)) - .set((updated.eq(naive_now()),)) + .set((last_refreshed_at.eq(naive_now()),)) .get_result::(conn) } -- 2.40.1 From af1204c0d00470660f463d09a9a61af910d1e9a0 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 2 Dec 2020 14:25:59 +0100 Subject: [PATCH 08/15] Add ApubObject trait in DB, with method read_from_apub_id() --- lemmy_api/src/community.rs | 3 +- .../src/activities/receive/community.rs | 6 +- lemmy_apub/src/activities/send/user.rs | 5 +- lemmy_apub/src/fetcher.rs | 5 +- lemmy_apub/src/inbox/community_inbox.rs | 5 +- lemmy_apub/src/inbox/mod.rs | 6 +- lemmy_apub/src/inbox/receive_for_community.rs | 2 +- lemmy_apub/src/inbox/shared_inbox.rs | 7 +-- lemmy_apub/src/inbox/user_inbox.rs | 3 +- lemmy_apub/src/objects/comment.rs | 1 + lemmy_apub/src/objects/community.rs | 3 +- lemmy_apub/src/objects/post.rs | 1 + lemmy_apub/src/objects/user.rs | 3 +- lemmy_db/src/comment.rs | 13 ++-- lemmy_db/src/community.rs | 17 +++--- lemmy_db/src/lib.rs | 6 ++ lemmy_db/src/post.rs | 61 ++++++++++--------- lemmy_db/src/user.rs | 19 +++--- 18 files changed, 95 insertions(+), 71 deletions(-) diff --git a/lemmy_api/src/community.rs b/lemmy_api/src/community.rs index 76242020..d7de0e6b 100644 --- a/lemmy_api/src/community.rs +++ b/lemmy_api/src/community.rs @@ -20,6 +20,7 @@ use lemmy_db::{ post::Post, site::*, user_view::*, + ApubObject, Bannable, Crud, Followable, @@ -129,7 +130,7 @@ impl Perform for CreateCommunity { let actor_id = make_apub_endpoint(EndpointType::Community, &data.name).to_string(); let actor_id_cloned = actor_id.to_owned(); let community_dupe = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &actor_id_cloned) + Community::read_from_apub_id(conn, &actor_id_cloned) }) .await?; if community_dupe.is_ok() { diff --git a/lemmy_apub/src/activities/receive/community.rs b/lemmy_apub/src/activities/receive/community.rs index ed43b33e..b1866283 100644 --- a/lemmy_apub/src/activities/receive/community.rs +++ b/lemmy_apub/src/activities/receive/community.rs @@ -4,7 +4,7 @@ use activitystreams::{ base::{AnyBase, ExtendsExt}, }; use anyhow::Context; -use lemmy_db::{community::Community, community_view::CommunityView}; +use lemmy_db::{community::Community, community_view::CommunityView, ApubObject}; use lemmy_structs::{blocking, community::CommunityResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation}; @@ -53,7 +53,7 @@ pub(crate) async fn receive_remove_community( .single_xsd_any_uri() .context(location_info!())?; let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, community_uri.as_str()) + Community::read_from_apub_id(conn, community_uri.as_str()) }) .await??; @@ -135,7 +135,7 @@ pub(crate) async fn receive_undo_remove_community( .single_xsd_any_uri() .context(location_info!())?; let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, community_uri.as_str()) + Community::read_from_apub_id(conn, community_uri.as_str()) }) .await??; diff --git a/lemmy_apub/src/activities/send/user.rs b/lemmy_apub/src/activities/send/user.rs index a94f241d..8c539c4b 100644 --- a/lemmy_apub/src/activities/send/user.rs +++ b/lemmy_apub/src/activities/send/user.rs @@ -16,6 +16,7 @@ use activitystreams::{ use lemmy_db::{ community::{Community, CommunityFollower, CommunityFollowerForm}, user::User_, + ApubObject, DbPool, Followable, }; @@ -46,7 +47,7 @@ impl ActorType for User_ { ) -> Result<(), LemmyError> { let follow_actor_id = follow_actor_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &follow_actor_id) + Community::read_from_apub_id(conn, &follow_actor_id) }) .await??; @@ -77,7 +78,7 @@ impl ActorType for User_ { ) -> Result<(), LemmyError> { let follow_actor_id = follow_actor_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &follow_actor_id) + Community::read_from_apub_id(conn, &follow_actor_id) }) .await??; diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index 0fb0cb10..a29c1fe9 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -22,6 +22,7 @@ use lemmy_db::{ post_view::PostView, user::User_, user_view::UserView, + ApubObject, Joinable, SearchType, }; @@ -236,7 +237,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user( ) -> Result { let apub_id_owned = apub_id.to_owned(); let user = blocking(context.pool(), move |conn| { - User_::read_from_actor_id(conn, apub_id_owned.as_ref()) + User_::read_from_apub_id(conn, apub_id_owned.as_ref()) }) .await?; @@ -314,7 +315,7 @@ pub(crate) async fn get_or_fetch_and_upsert_community( ) -> Result { let apub_id_owned = apub_id.to_owned(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, apub_id_owned.as_str()) + Community::read_from_apub_id(conn, apub_id_owned.as_str()) }) .await?; diff --git a/lemmy_apub/src/inbox/community_inbox.rs b/lemmy_apub/src/inbox/community_inbox.rs index 137f3fea..6acdfa0d 100644 --- a/lemmy_apub/src/inbox/community_inbox.rs +++ b/lemmy_apub/src/inbox/community_inbox.rs @@ -29,6 +29,7 @@ use lemmy_db::{ community::{Community, CommunityFollower, CommunityFollowerForm}, community_view::CommunityUserBanView, user::User_, + ApubObject, DbPool, Followable, }; @@ -116,7 +117,7 @@ pub(crate) async fn community_receive_message( // unconditionally. let actor_id = actor.actor_id_str(); let user = blocking(&context.pool(), move |conn| { - User_::read_from_actor_id(&conn, &actor_id) + User_::read_from_apub_id(&conn, &actor_id) }) .await??; check_community_or_site_ban(&user, &to_community, context.pool()).await?; @@ -240,7 +241,7 @@ async fn handle_undo_follow( verify_activity_domains_valid(&follow, &user_url, false)?; let user = blocking(&context.pool(), move |conn| { - User_::read_from_actor_id(&conn, user_url.as_str()) + User_::read_from_apub_id(&conn, user_url.as_str()) }) .await??; let community_follower_form = CommunityFollowerForm { diff --git a/lemmy_apub/src/inbox/mod.rs b/lemmy_apub/src/inbox/mod.rs index 4fdbb7a5..8b37f5be 100644 --- a/lemmy_apub/src/inbox/mod.rs +++ b/lemmy_apub/src/inbox/mod.rs @@ -12,7 +12,7 @@ use activitystreams::{ }; use actix_web::HttpRequest; use anyhow::{anyhow, Context}; -use lemmy_db::{activity::Activity, community::Community, user::User_, DbPool}; +use lemmy_db::{activity::Activity, community::Community, user::User_, ApubObject, DbPool}; use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; @@ -119,7 +119,7 @@ pub(crate) async fn is_addressed_to_local_user( ) -> Result { for url in to_and_cc { let url = url.to_string(); - let user = blocking(&pool, move |conn| User_::read_from_actor_id(&conn, &url)).await?; + let user = blocking(&pool, move |conn| User_::read_from_apub_id(&conn, &url)).await?; if let Ok(u) = user { if u.local { return Ok(true); @@ -141,7 +141,7 @@ pub(crate) async fn is_addressed_to_community_followers( if url.ends_with("/followers") { let community_url = url.replace("/followers", ""); let community = blocking(&pool, move |conn| { - Community::read_from_actor_id(&conn, &community_url) + Community::read_from_apub_id(&conn, &community_url) }) .await??; if !community.local { diff --git a/lemmy_apub/src/inbox/receive_for_community.rs b/lemmy_apub/src/inbox/receive_for_community.rs index b6dfa1e4..710cf17b 100644 --- a/lemmy_apub/src/inbox/receive_for_community.rs +++ b/lemmy_apub/src/inbox/receive_for_community.rs @@ -40,7 +40,7 @@ use activitystreams::{ }; use anyhow::Context; use diesel::result::Error::NotFound; -use lemmy_db::{comment::Comment, post::Post, site::Site, Crud}; +use lemmy_db::{comment::Comment, post::Post, site::Site, ApubObject, Crud}; use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; diff --git a/lemmy_apub/src/inbox/shared_inbox.rs b/lemmy_apub/src/inbox/shared_inbox.rs index dfd58366..9b5bdd6f 100644 --- a/lemmy_apub/src/inbox/shared_inbox.rs +++ b/lemmy_apub/src/inbox/shared_inbox.rs @@ -14,7 +14,7 @@ use crate::{ use activitystreams::{activity::ActorAndObject, prelude::*}; use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::Context; -use lemmy_db::{community::Community, DbPool}; +use lemmy_db::{community::Community, ApubObject, DbPool}; use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; @@ -135,10 +135,7 @@ async fn extract_local_community_from_destinations( ) -> Result, LemmyError> { for url in to_and_cc { let url = url.to_string(); - let community = blocking(&pool, move |conn| { - Community::read_from_actor_id(&conn, &url) - }) - .await?; + let community = blocking(&pool, move |conn| Community::read_from_apub_id(&conn, &url)).await?; if let Ok(c) = community { if c.local { return Ok(Some(c)); diff --git a/lemmy_apub/src/inbox/user_inbox.rs b/lemmy_apub/src/inbox/user_inbox.rs index dfcb2d61..76fa7d62 100644 --- a/lemmy_apub/src/inbox/user_inbox.rs +++ b/lemmy_apub/src/inbox/user_inbox.rs @@ -51,6 +51,7 @@ use lemmy_db::{ community::{Community, CommunityFollower}, private_message::PrivateMessage, user::User_, + ApubObject, Followable, }; use lemmy_structs::blocking; @@ -375,7 +376,7 @@ async fn find_community_or_private_message_by_id( ) -> Result { let ap_id = apub_id.to_string(); let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, &ap_id) + Community::read_from_apub_id(conn, &ap_id) }) .await?; if let Ok(c) = community { diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 1454a738..52e9320e 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -26,6 +26,7 @@ use lemmy_db::{ community::Community, post::Post, user::User_, + ApubObject, Crud, DbPool, }; diff --git a/lemmy_apub/src/objects/community.rs b/lemmy_apub/src/objects/community.rs index 57cc4737..eababf51 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -25,6 +25,7 @@ use lemmy_db::{ community::{Community, CommunityForm}, community_view::CommunityModeratorView, naive_now, + ApubObject, DbPool, }; use lemmy_structs::blocking; @@ -124,7 +125,7 @@ impl FromApub for Community { let domain = community_id.domain().context(location_info!())?; if domain == Settings::get().hostname { let community = blocking(context.pool(), move |conn| { - Community::read_from_actor_id(conn, community_id.as_str()) + Community::read_from_apub_id(conn, community_id.as_str()) }) .await??; Ok(community) diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index 7151ee33..98a9c2ee 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -23,6 +23,7 @@ use lemmy_db::{ community::Community, post::{Post, PostForm}, user::User_, + ApubObject, Crud, DbPool, }; diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index 7162a117..4fce30a6 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -21,6 +21,7 @@ use anyhow::Context; use lemmy_db::{ naive_now, user::{UserForm, User_}, + ApubObject, DbPool, }; use lemmy_structs::blocking; @@ -101,7 +102,7 @@ impl FromApub for User_ { let domain = user_id.domain().context(location_info!())?; if domain == Settings::get().hostname { let user = blocking(context.pool(), move |conn| { - User_::read_from_actor_id(conn, user_id.as_str()) + User_::read_from_apub_id(conn, user_id.as_str()) }) .await??; Ok(user) diff --git a/lemmy_db/src/comment.rs b/lemmy_db/src/comment.rs index 9b092825..e9568bac 100644 --- a/lemmy_db/src/comment.rs +++ b/lemmy_db/src/comment.rs @@ -2,6 +2,7 @@ use super::post::Post; use crate::{ naive_now, schema::{comment, comment_like, comment_saved}, + ApubObject, Crud, Likeable, Saveable, @@ -86,6 +87,13 @@ impl Crud for Comment { } } +impl ApubObject for Comment { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::comment::dsl::*; + comment.filter(ap_id.eq(object_id)).first::(conn) + } +} + impl Comment { pub fn update_ap_id( conn: &PgConnection, @@ -99,11 +107,6 @@ impl Comment { .get_result::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::comment::dsl::*; - comment.filter(ap_id.eq(object_id)).first::(conn) - } - pub fn permadelete_for_creator( conn: &PgConnection, for_creator_id: i32, diff --git a/lemmy_db/src/community.rs b/lemmy_db/src/community.rs index 5f76d514..5c3ee551 100644 --- a/lemmy_db/src/community.rs +++ b/lemmy_db/src/community.rs @@ -1,6 +1,7 @@ use crate::{ naive_now, schema::{community, community_follower, community_moderator, community_user_ban}, + ApubObject, Bannable, Crud, Followable, @@ -83,6 +84,15 @@ impl Crud for Community { } } +impl ApubObject for Community { + fn read_from_apub_id(conn: &PgConnection, for_actor_id: &str) -> Result { + use crate::schema::community::dsl::*; + community + .filter(actor_id.eq(for_actor_id)) + .first::(conn) + } +} + impl Community { pub fn read_from_name(conn: &PgConnection, community_name: &str) -> Result { use crate::schema::community::dsl::*; @@ -92,13 +102,6 @@ impl Community { .first::(conn) } - pub fn read_from_actor_id(conn: &PgConnection, for_actor_id: &str) -> Result { - use crate::schema::community::dsl::*; - community - .filter(actor_id.eq(for_actor_id)) - .first::(conn) - } - pub fn update_deleted( conn: &PgConnection, community_id: i32, diff --git a/lemmy_db/src/lib.rs b/lemmy_db/src/lib.rs index bad646d1..e9c67671 100644 --- a/lemmy_db/src/lib.rs +++ b/lemmy_db/src/lib.rs @@ -124,6 +124,12 @@ pub trait Reportable { Self: Sized; } +pub trait ApubObject { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result + where + Self: Sized; +} + pub trait MaybeOptional { fn get_optional(self) -> Option; } diff --git a/lemmy_db/src/post.rs b/lemmy_db/src/post.rs index 787d5e6c..261d5d93 100644 --- a/lemmy_db/src/post.rs +++ b/lemmy_db/src/post.rs @@ -1,6 +1,7 @@ use crate::{ naive_now, schema::{post, post_like, post_read, post_saved}, + ApubObject, Crud, Likeable, Readable, @@ -62,6 +63,37 @@ impl PostForm { } } +impl Crud for Post { + fn read(conn: &PgConnection, post_id: i32) -> Result { + use crate::schema::post::dsl::*; + post.find(post_id).first::(conn) + } + + fn delete(conn: &PgConnection, post_id: i32) -> Result { + use crate::schema::post::dsl::*; + diesel::delete(post.find(post_id)).execute(conn) + } + + fn create(conn: &PgConnection, new_post: &PostForm) -> Result { + use crate::schema::post::dsl::*; + insert_into(post).values(new_post).get_result::(conn) + } + + fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result { + use crate::schema::post::dsl::*; + diesel::update(post.find(post_id)) + .set(new_post) + .get_result::(conn) + } +} + +impl ApubObject for Post { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::post::dsl::*; + post.filter(ap_id.eq(object_id)).first::(conn) + } +} + impl Post { pub fn read(conn: &PgConnection, post_id: i32) -> Result { use crate::schema::post::dsl::*; @@ -81,11 +113,6 @@ impl Post { .load::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::post::dsl::*; - post.filter(ap_id.eq(object_id)).first::(conn) - } - pub fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result { use crate::schema::post::dsl::*; @@ -189,30 +216,6 @@ impl Post { } } -impl Crud for Post { - fn read(conn: &PgConnection, post_id: i32) -> Result { - use crate::schema::post::dsl::*; - post.find(post_id).first::(conn) - } - - fn delete(conn: &PgConnection, post_id: i32) -> Result { - use crate::schema::post::dsl::*; - diesel::delete(post.find(post_id)).execute(conn) - } - - fn create(conn: &PgConnection, new_post: &PostForm) -> Result { - use crate::schema::post::dsl::*; - insert_into(post).values(new_post).get_result::(conn) - } - - fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result { - use crate::schema::post::dsl::*; - diesel::update(post.find(post_id)) - .set(new_post) - .get_result::(conn) - } -} - #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] #[belongs_to(Post)] #[table_name = "post_like"] diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index 4733fdfe..ada535e3 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -2,6 +2,7 @@ use crate::{ is_email_regex, naive_now, schema::{user_, user_::dsl::*}, + ApubObject, Crud, }; use bcrypt::{hash, DEFAULT_COST}; @@ -89,6 +90,16 @@ impl Crud for User_ { } } +impl ApubObject for User_ { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + use crate::schema::user_::dsl::*; + user_ + .filter(deleted.eq(false)) + .filter(actor_id.eq(object_id)) + .first::(conn) + } +} + impl User_ { pub fn register(conn: &PgConnection, form: &UserForm) -> Result { let mut edited_user = form.clone(); @@ -135,14 +146,6 @@ impl User_ { .get_result::(conn) } - pub fn read_from_actor_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::user_::dsl::*; - user_ - .filter(deleted.eq(false)) - .filter(actor_id.eq(object_id)) - .first::(conn) - } - pub fn find_by_email_or_username( conn: &PgConnection, username_or_email: &str, -- 2.40.1 From 7649dd048bf18212c3b528973a0d92319a4bdabb Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 2 Dec 2020 15:08:43 +0100 Subject: [PATCH 09/15] Create shared, generic implementation for `FromApub`, prefer local data --- lemmy_apub/src/objects/comment.rs | 38 +++++++------------- lemmy_apub/src/objects/community.rs | 25 ++----------- lemmy_apub/src/objects/mod.rs | 44 ++++++++++++++++++++--- lemmy_apub/src/objects/post.rs | 21 ++--------- lemmy_apub/src/objects/private_message.rs | 25 +++---------- lemmy_apub/src/objects/user.rs | 4 +-- lemmy_db/src/private_message.rs | 21 ++++++----- 7 files changed, 77 insertions(+), 101 deletions(-) diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 52e9320e..6d293394 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -8,6 +8,7 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, FromApub, @@ -26,14 +27,12 @@ use lemmy_db::{ community::Community, post::Post, user::User_, - ApubObject, Crud, DbPool, }; use lemmy_structs::blocking; use lemmy_utils::{ location_info, - settings::Settings, utils::{convert_datetime, remove_slurs}, LemmyError, }; @@ -102,38 +101,27 @@ impl FromApub for Comment { expected_domain: Option, request_counter: &mut i32, ) -> Result { - // TODO: we should move read_from_apub_id() and upsert() into traits so we can make a generic - // function to handle all this (shared with User_::from_apub etc) - let comment_id = note.id_unchecked().context(location_info!())?.to_owned(); - 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).await?; - let post_id = comment_form.post_id; - let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - if post.locked { - return Err(anyhow!("Post is locked").into()); - } + let comment: Comment = + get_object_from_apub(note, context, expected_domain, request_counter).await?; - let comment = blocking(context.pool(), move |conn| { - Comment::upsert(conn, &comment_form) + let post_id = comment.post_id; + let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; + if post.locked { + // This is not very efficient because a comment gets inserted just to be deleted right + // afterwards, but it seems to be the easiest way to implement it. + blocking(context.pool(), move |conn| { + Comment::delete(conn, comment.id) }) .await??; + return Err(anyhow!("Post is locked").into()); + } else { Ok(comment) } } } #[async_trait::async_trait(?Send)] -impl FromApubToForm for CommentForm { - type ApubType = NoteExt; - +impl FromApubToForm for CommentForm { 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 eababf51..fe05de9e 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -4,6 +4,7 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, FromApub, @@ -25,13 +26,11 @@ use lemmy_db::{ community::{Community, CommunityForm}, community_view::CommunityModeratorView, naive_now, - ApubObject, DbPool, }; use lemmy_structs::blocking; use lemmy_utils::{ location_info, - settings::Settings, utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; @@ -121,30 +120,12 @@ impl FromApub for Community { expected_domain: Option, request_counter: &mut i32, ) -> Result { - let community_id = group.id_unchecked().context(location_info!())?.to_owned(); - let domain = community_id.domain().context(location_info!())?; - if domain == Settings::get().hostname { - let community = blocking(context.pool(), move |conn| { - Community::read_from_apub_id(conn, community_id.as_str()) - }) - .await??; - Ok(community) - } else { - let community_form = - CommunityForm::from_apub(group, context, expected_domain, request_counter).await?; - let community = blocking(context.pool(), move |conn| { - Community::upsert(conn, &community_form) - }) - .await??; - Ok(community) - } + get_object_from_apub(group, context, expected_domain, request_counter).await } } #[async_trait::async_trait(?Send)] -impl FromApubToForm for CommunityForm { - type ApubType = GroupExt; - +impl FromApubToForm for CommunityForm { async fn from_apub( group: &GroupExt, context: &LemmyContext, diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index 8258e746..6a017505 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -7,7 +7,8 @@ use activitystreams::{ }; use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; -use lemmy_db::DbPool; +use lemmy_db::{ApubObject, Crud, DbPool}; +use lemmy_structs::blocking; use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -46,10 +47,9 @@ pub(crate) trait FromApub { } #[async_trait::async_trait(?Send)] -pub(in crate::objects) trait FromApubToForm { - type ApubType; +pub(in crate::objects) trait FromApubToForm { async fn from_apub( - apub: &Self::ApubType, + apub: &ApubType, context: &LemmyContext, expected_domain: Option, request_counter: &mut i32, @@ -169,3 +169,39 @@ pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), L Ok(()) } } + +/// Converts an ActivityPub object (eg `Note`) to a database object (eg `Comment`). If an object +/// with the same ActivityPub ID already exists in the database, it is returned directly. Otherwise +/// the apub object is parsed, inserted and returned. +pub(in crate::objects) async fn get_object_from_apub( + from: &From, + context: &LemmyContext, + expected_domain: Option, + request_counter: &mut i32, +) -> Result +where + From: BaseExt, + To: ApubObject + Crud + Send + 'static, + ToForm: FromApubToForm + Send + 'static, +{ + let object_id = from.id_unchecked().context(location_info!())?.to_owned(); + let object_in_database = blocking(context.pool(), move |conn| { + To::read_from_apub_id(conn, object_id.as_str()) + }) + .await?; + + // if we already have the object in our database, return that directly + if let Ok(to) = object_in_database { + Ok(to) + } + // if we dont have it, parse from apub and insert into database + // TODO: this is insecure, a `Like/Post` could result in a non-existent post from a different + // instance being inserted into our database. we should request the object over http in that + // case. this might happen exactly in the case where expected_domain = None, but i'm not sure. + else { + let to_form = ToForm::from_apub(&from, context, expected_domain, request_counter).await?; + + let to = blocking(context.pool(), move |conn| To::create(conn, &to_form)).await??; + Ok(to) + } +} diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index 98a9c2ee..9c68c1c9 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -4,6 +4,7 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, FromApub, @@ -23,7 +24,6 @@ use lemmy_db::{ community::Community, post::{Post, PostForm}, user::User_, - ApubObject, Crud, DbPool, }; @@ -31,7 +31,6 @@ use lemmy_structs::blocking; use lemmy_utils::{ location_info, request::fetch_iframely_and_pictrs_data, - settings::Settings, utils::{check_slurs, convert_datetime, remove_slurs}, LemmyError, }; @@ -113,26 +112,12 @@ impl FromApub for Post { expected_domain: Option, request_counter: &mut i32, ) -> Result { - let post_id = page.id_unchecked().context(location_info!())?.to_owned(); - let domain = post_id.domain().context(location_info!())?; - if domain == Settings::get().hostname { - let post = blocking(context.pool(), move |conn| { - Post::read_from_apub_id(conn, post_id.as_str()) - }) - .await??; - Ok(post) - } else { - let post_form = PostForm::from_apub(page, context, expected_domain, request_counter).await?; - let post = blocking(context.pool(), move |conn| Post::upsert(conn, &post_form)).await??; - Ok(post) - } + get_object_from_apub(page, context, expected_domain, request_counter).await } } #[async_trait::async_trait(?Send)] -impl FromApubToForm for PostForm { - type ApubType = PageExt; - +impl FromApubToForm for PostForm { 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 80bc4e66..84b5f980 100644 --- a/lemmy_apub/src/objects/private_message.rs +++ b/lemmy_apub/src/objects/private_message.rs @@ -5,6 +5,7 @@ use crate::{ objects::{ check_object_domain, create_tombstone, + get_object_from_apub, get_source_markdown_value, set_content_and_source, FromApub, @@ -25,7 +26,7 @@ use lemmy_db::{ DbPool, }; use lemmy_structs::blocking; -use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError}; +use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -73,30 +74,12 @@ impl FromApub for PrivateMessage { expected_domain: Option, request_counter: &mut i32, ) -> Result { - let private_message_id = note.id_unchecked().context(location_info!())?.to_owned(); - let domain = private_message_id.domain().context(location_info!())?; - if domain == Settings::get().hostname { - let private_message = blocking(context.pool(), move |conn| { - PrivateMessage::read_from_apub_id(conn, private_message_id.as_str()) - }) - .await??; - Ok(private_message) - } else { - let private_message_form = - PrivateMessageForm::from_apub(note, context, expected_domain, request_counter).await?; - let private_message = blocking(context.pool(), move |conn| { - PrivateMessage::upsert(conn, &private_message_form) - }) - .await??; - Ok(private_message) - } + get_object_from_apub(note, context, expected_domain, request_counter).await } } #[async_trait::async_trait(?Send)] -impl FromApubToForm for PrivateMessageForm { - type ApubType = NoteExt; - +impl FromApubToForm for PrivateMessageForm { async fn from_apub( note: &NoteExt, context: &LemmyContext, diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index 4fce30a6..f65df242 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -116,9 +116,7 @@ impl FromApub for User_ { } #[async_trait::async_trait(?Send)] -impl FromApubToForm for UserForm { - type ApubType = PersonExt; - +impl FromApubToForm for UserForm { async fn from_apub( person: &PersonExt, _context: &LemmyContext, diff --git a/lemmy_db/src/private_message.rs b/lemmy_db/src/private_message.rs index 503a26ab..e8f02150 100644 --- a/lemmy_db/src/private_message.rs +++ b/lemmy_db/src/private_message.rs @@ -1,4 +1,4 @@ -use crate::{naive_now, schema::private_message, Crud}; +use crate::{naive_now, schema::private_message, ApubObject, Crud}; use diesel::{dsl::*, result::Error, *}; #[derive(Queryable, Identifiable, PartialEq, Debug)] @@ -55,6 +55,18 @@ impl Crud for PrivateMessage { } } +impl ApubObject for PrivateMessage { + fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result + where + Self: Sized, + { + use crate::schema::private_message::dsl::*; + private_message + .filter(ap_id.eq(object_id)) + .first::(conn) + } +} + impl PrivateMessage { pub fn update_ap_id( conn: &PgConnection, @@ -68,13 +80,6 @@ impl PrivateMessage { .get_result::(conn) } - pub fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { - use crate::schema::private_message::dsl::*; - private_message - .filter(ap_id.eq(object_id)) - .first::(conn) - } - pub fn update_content( conn: &PgConnection, private_message_id: i32, -- 2.40.1 From 32c4d3224c1bc80e2a684bf1301bf4b1a2985d28 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 2 Dec 2020 16:55:53 +0100 Subject: [PATCH 10/15] Check for community ban when parsing post/comment (fixes #1287) --- lemmy_apub/src/inbox/community_inbox.rs | 2 +- lemmy_apub/src/objects/comment.rs | 3 +++ lemmy_apub/src/objects/mod.rs | 29 ++++++++++++++++++++++++- lemmy_apub/src/objects/post.rs | 2 ++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lemmy_apub/src/inbox/community_inbox.rs b/lemmy_apub/src/inbox/community_inbox.rs index 6acdfa0d..ad6eaffb 100644 --- a/lemmy_apub/src/inbox/community_inbox.rs +++ b/lemmy_apub/src/inbox/community_inbox.rs @@ -259,7 +259,7 @@ async fn handle_undo_follow( Ok(()) } -async fn check_community_or_site_ban( +pub(crate) async fn check_community_or_site_ban( user: &User_, community: &Community, pool: &DbPool, diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 6d293394..9ff63cbd 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -7,6 +7,7 @@ use crate::{ }, objects::{ check_object_domain, + check_object_for_community_or_site_ban, create_tombstone, get_object_from_apub, get_source_markdown_value, @@ -101,6 +102,8 @@ impl FromApub for Comment { expected_domain: Option, request_counter: &mut i32, ) -> Result { + check_object_for_community_or_site_ban(note, context, request_counter).await?; + let comment: Comment = get_object_from_apub(note, context, expected_domain, request_counter).await?; diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index 6a017505..f7db59c7 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -1,4 +1,8 @@ -use crate::check_is_apub_id_valid; +use crate::{ + check_is_apub_id_valid, + fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, + inbox::community_inbox::check_community_or_site_ban, +}; use activitystreams::{ base::{AsBase, BaseExt, ExtendsExt}, markers::Base, @@ -205,3 +209,26 @@ where Ok(to) } } + +pub(in crate::objects) async fn check_object_for_community_or_site_ban( + object: &T, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result<(), LemmyError> +where + T: ObjectExt, +{ + let user_id = object + .attributed_to() + .context(location_info!())? + .as_single_xsd_any_uri() + .context(location_info!())?; + let user = get_or_fetch_and_upsert_user(user_id, context, request_counter).await?; + let community_id = object + .to() + .context(location_info!())? + .as_single_xsd_any_uri() + .context(location_info!())?; + let community = get_or_fetch_and_upsert_community(community_id, context, request_counter).await?; + check_community_or_site_ban(&user, &community, context.pool()).await +} diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index 9c68c1c9..3ca8650d 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -3,6 +3,7 @@ use crate::{ fetcher::{get_or_fetch_and_upsert_community, get_or_fetch_and_upsert_user}, objects::{ check_object_domain, + check_object_for_community_or_site_ban, create_tombstone, get_object_from_apub, get_source_markdown_value, @@ -112,6 +113,7 @@ impl FromApub for Post { expected_domain: Option, request_counter: &mut i32, ) -> Result { + check_object_for_community_or_site_ban(page, context, request_counter).await?; get_object_from_apub(page, context, expected_domain, request_counter).await } } -- 2.40.1 From 32f69775c3f42e9b211edffc5013bc1fa67d3315 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 2 Dec 2020 18:03:26 +0100 Subject: [PATCH 11/15] Fix tests (changes in get_object_from_apub() prevented `Update` from working) --- lemmy_apub/src/objects/mod.rs | 19 ++++++++++--------- lemmy_db/src/comment.rs | 22 +++++++++++----------- lemmy_db/src/community.rs | 22 +++++++++++----------- lemmy_db/src/lib.rs | 5 ++++- lemmy_db/src/post.rs | 22 +++++++++++----------- lemmy_db/src/private_message.rs | 26 +++++++++++--------------- lemmy_db/src/user.rs | 20 ++++++++++---------- 7 files changed, 68 insertions(+), 68 deletions(-) diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index f7db59c7..fbe89b09 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -13,7 +13,7 @@ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use lemmy_db::{ApubObject, Crud, DbPool}; use lemmy_structs::blocking; -use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; +use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -185,18 +185,19 @@ pub(in crate::objects) async fn get_object_from_apub( ) -> Result where From: BaseExt, - To: ApubObject + Crud + Send + 'static, + To: ApubObject + Crud + Send + 'static, ToForm: FromApubToForm + Send + 'static, { let object_id = from.id_unchecked().context(location_info!())?.to_owned(); - let object_in_database = blocking(context.pool(), move |conn| { - To::read_from_apub_id(conn, object_id.as_str()) - }) - .await?; + let domain = object_id.domain().context(location_info!())?; // if we already have the object in our database, return that directly - if let Ok(to) = object_in_database { - Ok(to) + if Settings::get().hostname == domain { + let object = blocking(context.pool(), move |conn| { + To::read_from_apub_id(conn, object_id.as_str()) + }) + .await??; + Ok(object) } // if we dont have it, parse from apub and insert into database // TODO: this is insecure, a `Like/Post` could result in a non-existent post from a different @@ -205,7 +206,7 @@ where else { let to_form = ToForm::from_apub(&from, context, expected_domain, request_counter).await?; - let to = blocking(context.pool(), move |conn| To::create(conn, &to_form)).await??; + let to = blocking(context.pool(), move |conn| To::upsert(conn, &to_form)).await??; Ok(to) } } diff --git a/lemmy_db/src/comment.rs b/lemmy_db/src/comment.rs index e9568bac..f54ddd10 100644 --- a/lemmy_db/src/comment.rs +++ b/lemmy_db/src/comment.rs @@ -87,11 +87,21 @@ impl Crud for Comment { } } -impl ApubObject for Comment { +impl ApubObject for Comment { fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { use crate::schema::comment::dsl::*; comment.filter(ap_id.eq(object_id)).first::(conn) } + + fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result { + use crate::schema::comment::dsl::*; + insert_into(comment) + .values(comment_form) + .on_conflict(ap_id) + .do_update() + .set(comment_form) + .get_result::(conn) + } } impl Comment { @@ -171,16 +181,6 @@ impl Comment { .set((content.eq(new_content), updated.eq(naive_now()))) .get_result::(conn) } - - pub fn upsert(conn: &PgConnection, comment_form: &CommentForm) -> Result { - use crate::schema::comment::dsl::*; - insert_into(comment) - .values(comment_form) - .on_conflict(ap_id) - .do_update() - .set(comment_form) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)] diff --git a/lemmy_db/src/community.rs b/lemmy_db/src/community.rs index 5c3ee551..be40da34 100644 --- a/lemmy_db/src/community.rs +++ b/lemmy_db/src/community.rs @@ -84,13 +84,23 @@ impl Crud for Community { } } -impl ApubObject for Community { +impl ApubObject for Community { fn read_from_apub_id(conn: &PgConnection, for_actor_id: &str) -> Result { use crate::schema::community::dsl::*; community .filter(actor_id.eq(for_actor_id)) .first::(conn) } + + fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result { + use crate::schema::community::dsl::*; + insert_into(community) + .values(community_form) + .on_conflict(actor_id) + .do_update() + .set(community_form) + .get_result::(conn) + } } impl Community { @@ -168,16 +178,6 @@ impl Community { .unwrap_or_default() .contains(&user_id) } - - pub fn upsert(conn: &PgConnection, community_form: &CommunityForm) -> Result { - use crate::schema::community::dsl::*; - insert_into(community) - .values(community_form) - .on_conflict(actor_id) - .do_update() - .set(community_form) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/lemmy_db/src/lib.rs b/lemmy_db/src/lib.rs index e9c67671..0ca4826a 100644 --- a/lemmy_db/src/lib.rs +++ b/lemmy_db/src/lib.rs @@ -124,10 +124,13 @@ pub trait Reportable { Self: Sized; } -pub trait ApubObject { +pub trait ApubObject { fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result where Self: Sized; + fn upsert(conn: &PgConnection, user_form: &T) -> Result + where + Self: Sized; } pub trait MaybeOptional { diff --git a/lemmy_db/src/post.rs b/lemmy_db/src/post.rs index 261d5d93..530f475b 100644 --- a/lemmy_db/src/post.rs +++ b/lemmy_db/src/post.rs @@ -87,11 +87,21 @@ impl Crud for Post { } } -impl ApubObject for Post { +impl ApubObject for Post { fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { use crate::schema::post::dsl::*; post.filter(ap_id.eq(object_id)).first::(conn) } + + fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result { + use crate::schema::post::dsl::*; + insert_into(post) + .values(post_form) + .on_conflict(ap_id) + .do_update() + .set(post_form) + .get_result::(conn) + } } impl Post { @@ -204,16 +214,6 @@ impl Post { pub fn is_post_creator(user_id: i32, post_creator_id: i32) -> bool { user_id == post_creator_id } - - pub fn upsert(conn: &PgConnection, post_form: &PostForm) -> Result { - use crate::schema::post::dsl::*; - insert_into(post) - .values(post_form) - .on_conflict(ap_id) - .do_update() - .set(post_form) - .get_result::(conn) - } } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/lemmy_db/src/private_message.rs b/lemmy_db/src/private_message.rs index e8f02150..0e1aef10 100644 --- a/lemmy_db/src/private_message.rs +++ b/lemmy_db/src/private_message.rs @@ -55,7 +55,7 @@ impl Crud for PrivateMessage { } } -impl ApubObject for PrivateMessage { +impl ApubObject for PrivateMessage { fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result where Self: Sized, @@ -65,6 +65,16 @@ impl ApubObject for PrivateMessage { .filter(ap_id.eq(object_id)) .first::(conn) } + + fn upsert(conn: &PgConnection, private_message_form: &PrivateMessageForm) -> Result { + use crate::schema::private_message::dsl::*; + insert_into(private_message) + .values(private_message_form) + .on_conflict(ap_id) + .do_update() + .set(private_message_form) + .get_result::(conn) + } } impl PrivateMessage { @@ -123,20 +133,6 @@ impl PrivateMessage { .set(read.eq(true)) .get_results::(conn) } - - // TODO use this - pub fn upsert( - conn: &PgConnection, - private_message_form: &PrivateMessageForm, - ) -> Result { - use crate::schema::private_message::dsl::*; - insert_into(private_message) - .values(private_message_form) - .on_conflict(ap_id) - .do_update() - .set(private_message_form) - .get_result::(conn) - } } #[cfg(test)] diff --git a/lemmy_db/src/user.rs b/lemmy_db/src/user.rs index ada535e3..d8e833e6 100644 --- a/lemmy_db/src/user.rs +++ b/lemmy_db/src/user.rs @@ -90,7 +90,7 @@ impl Crud for User_ { } } -impl ApubObject for User_ { +impl ApubObject for User_ { fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { use crate::schema::user_::dsl::*; user_ @@ -98,6 +98,15 @@ impl ApubObject for User_ { .filter(actor_id.eq(object_id)) .first::(conn) } + + fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result { + insert_into(user_) + .values(user_form) + .on_conflict(actor_id) + .do_update() + .set(user_form) + .get_result::(conn) + } } impl User_ { @@ -182,15 +191,6 @@ impl User_ { ) } - pub fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result { - insert_into(user_) - .values(user_form) - .on_conflict(actor_id) - .do_update() - .set(user_form) - .get_result::(conn) - } - pub fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result { diesel::update(user_.find(user_id)) .set((last_refreshed_at.eq(naive_now()),)) -- 2.40.1 From 429b7f6e5c61752e679a55b9b67d8bad9894b9b9 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 3 Dec 2020 14:35:34 +0100 Subject: [PATCH 12/15] Support parsing `like.object` either as URL or object --- lemmy_apub/src/activities/receive/comment.rs | 40 +++++++++-------- .../src/activities/receive/comment_undo.rs | 31 ++++++------- lemmy_apub/src/activities/receive/mod.rs | 25 +++++++++++ lemmy_apub/src/activities/receive/post.rs | 39 ++++++++-------- .../src/activities/receive/post_undo.rs | 31 ++++++------- .../src/activities/receive/private_message.rs | 4 +- lemmy_apub/src/fetcher.rs | 44 ++++++------------- lemmy_apub/src/objects/comment.rs | 4 +- lemmy_apub/src/objects/community.rs | 4 +- lemmy_apub/src/objects/mod.rs | 26 ++++------- lemmy_apub/src/objects/post.rs | 4 +- lemmy_apub/src/objects/private_message.rs | 4 +- lemmy_apub/src/objects/user.rs | 4 +- 13 files changed, 128 insertions(+), 132 deletions(-) diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index da29a3b7..1d0260f7 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -1,6 +1,20 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt}; +use crate::{ + activities::receive::{get_actor_as_user, get_like_object_id}, + fetcher::get_or_fetch_and_insert_comment, + objects::FromApub, + ActorType, + NoteExt, +}; use activitystreams::{ - activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, + activity::{ + kind::{DislikeType, LikeType}, + ActorAndObjectRefExt, + Create, + Dislike, + Like, + Remove, + Update, + }, base::ExtendsExt, }; use anyhow::Context; @@ -23,7 +37,7 @@ pub(crate) async fn receive_create_comment( let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -66,7 +80,7 @@ pub(crate) async fn receive_update_comment( .context(location_info!())?; let user = get_actor_as_user(&update, context, request_counter).await?; - let comment = Comment::from_apub(¬e, context, Some(user.actor_id()?), request_counter).await?; + let comment = Comment::from_apub(¬e, context, user.actor_id()?, request_counter).await?; let comment_id = comment.id; let post_id = comment.post_id; @@ -102,11 +116,9 @@ pub(crate) async fn receive_like_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; let user = get_actor_as_user(&like, context, request_counter).await?; - - let comment = Comment::from_apub(¬e, context, None, request_counter).await?; + let comment_id = get_like_object_id::(&like)?; + let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { @@ -150,17 +162,9 @@ pub(crate) async fn receive_dislike_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let note = NoteExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; let user = get_actor_as_user(&dislike, context, request_counter).await?; - - let comment = Comment::from_apub(¬e, context, None, request_counter).await?; + let comment_id = get_like_object_id::(&dislike)?; + let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index 2ccec087..da924696 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,13 +1,18 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, NoteExt}; -use activitystreams::{activity::*, prelude::*}; -use anyhow::Context; +use crate::{ + activities::receive::{get_actor_as_user, get_like_object_id}, + fetcher::get_or_fetch_and_insert_comment, +}; +use activitystreams::activity::{ + kind::{DislikeType, LikeType}, + *, +}; use lemmy_db::{ comment::{Comment, CommentLike}, comment_view::CommentView, Likeable, }; use lemmy_structs::{blocking, comment::CommentResponse}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_comment( @@ -16,10 +21,8 @@ pub(crate) async fn receive_undo_like_comment( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let note = NoteExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let comment = Comment::from_apub(¬e, context, None, request_counter).await?; + let comment_id = get_like_object_id::(like)?; + let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let user_id = user.id; @@ -57,16 +60,8 @@ pub(crate) async fn receive_undo_dislike_comment( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let note = NoteExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let comment = Comment::from_apub(¬e, context, None, request_counter).await?; + let comment_id = get_like_object_id::(dislike)?; + let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let user_id = user.id; diff --git a/lemmy_apub/src/activities/receive/mod.rs b/lemmy_apub/src/activities/receive/mod.rs index 1f17fe9f..d67f12fa 100644 --- a/lemmy_apub/src/activities/receive/mod.rs +++ b/lemmy_apub/src/activities/receive/mod.rs @@ -79,3 +79,28 @@ where Ok(()) } + +pub(in crate::activities::receive) fn get_like_object_id( + like_or_dislike: &Activity, +) -> Result +where + Activity: ActorAndObjectRefExt, +{ + // For backwards compatibility with older Lemmy versions where like.object contains a full + // post/comment. This can be removed after some time, using + // `activity.oject().as_single_xsd_any_uri()` instead. + let object = like_or_dislike.object(); + if let Some(xsd_uri) = object.as_single_xsd_any_uri() { + Ok(xsd_uri.to_owned()) + } else { + Ok( + object + .to_owned() + .one() + .context(location_info!())? + .id() + .context(location_info!())? + .to_owned(), + ) + } +} diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index d1c92157..04d83d37 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -1,6 +1,19 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt}; +use crate::{ + activities::receive::{get_actor_as_user, get_like_object_id}, + fetcher::get_or_fetch_and_insert_post, + objects::FromApub, + ActorType, + PageExt, +}; use activitystreams::{ - activity::{Create, Dislike, Like, Remove, Update}, + activity::{ + kind::{DislikeType, LikeType}, + Create, + Dislike, + Like, + Remove, + Update, + }, prelude::*, }; use anyhow::Context; @@ -22,7 +35,7 @@ pub(crate) async fn receive_create_post( let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = Post::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; + let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?; // Refetch the view let post_id = post.id; @@ -51,7 +64,7 @@ pub(crate) async fn receive_update_post( let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = Post::from_apub(&page, context, Some(user.actor_id()?), request_counter).await?; + let post = Post::from_apub(&page, context, user.actor_id()?, request_counter).await?; let post_id = post.id; // Refetch the view @@ -77,10 +90,8 @@ pub(crate) async fn receive_like_post( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&like, context, request_counter).await?; - let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let post = Post::from_apub(&page, context, None, request_counter).await?; + let post_id = get_like_object_id::(&like)?; + let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { @@ -118,16 +129,8 @@ pub(crate) async fn receive_dislike_post( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&dislike, context, request_counter).await?; - let page = PageExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let post = Post::from_apub(&page, context, None, request_counter).await?; + let post_id = get_like_object_id::(&dislike)?; + let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index aced5f4b..cf2f447b 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,13 +1,18 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, PageExt}; -use activitystreams::{activity::*, prelude::*}; -use anyhow::Context; +use crate::{ + activities::receive::{get_actor_as_user, get_like_object_id}, + fetcher::get_or_fetch_and_insert_post, +}; +use activitystreams::activity::{ + kind::{DislikeType, LikeType}, + *, +}; use lemmy_db::{ post::{Post, PostLike}, post_view::PostView, Likeable, }; use lemmy_structs::{blocking, post::PostResponse}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_post( @@ -16,10 +21,8 @@ pub(crate) async fn receive_undo_like_post( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let page = PageExt::from_any_base(like.object().to_owned().one().context(location_info!())?)? - .context(location_info!())?; - - let post = Post::from_apub(&page, context, None, request_counter).await?; + let post_id = get_like_object_id::(&like)?; + let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let user_id = user.id; @@ -51,16 +54,8 @@ pub(crate) async fn receive_undo_dislike_post( request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let page = PageExt::from_any_base( - dislike - .object() - .to_owned() - .one() - .context(location_info!())?, - )? - .context(location_info!())?; - - let post = Post::from_apub(&page, context, None, request_counter).await?; + let post_id = get_like_object_id::(&dislike)?; + let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let user_id = user.id; diff --git a/lemmy_apub/src/activities/receive/private_message.rs b/lemmy_apub/src/activities/receive/private_message.rs index 74ce004a..25ccc520 100644 --- a/lemmy_apub/src/activities/receive/private_message.rs +++ b/lemmy_apub/src/activities/receive/private_message.rs @@ -37,7 +37,7 @@ pub(crate) async fn receive_create_private_message( .context(location_info!())?; let private_message = - PrivateMessage::from_apub(¬e, context, Some(expected_domain), request_counter).await?; + PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?; let message = blocking(&context.pool(), move |conn| { PrivateMessageView::read(conn, private_message.id) @@ -74,7 +74,7 @@ pub(crate) async fn receive_update_private_message( let note = NoteExt::from_any_base(object)?.context(location_info!())?; let private_message = - PrivateMessage::from_apub(¬e, context, Some(expected_domain), request_counter).await?; + PrivateMessage::from_apub(¬e, context, expected_domain, request_counter).await?; let private_message_id = private_message.id; let message = blocking(&context.pool(), move |conn| { diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index a29c1fe9..ad977f5b 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -184,7 +184,7 @@ pub async fn search_by_apub_id( response } SearchAcceptedObjects::Page(p) => { - let p = Post::from_apub(&p, context, Some(query_url), recursion_counter).await?; + let p = Post::from_apub(&p, context, query_url, recursion_counter).await?; response.posts = vec![blocking(context.pool(), move |conn| PostView::read(conn, p.id, None)).await??]; @@ -192,7 +192,7 @@ pub async fn search_by_apub_id( response } SearchAcceptedObjects::Comment(c) => { - let c = Comment::from_apub(&c, context, Some(query_url), recursion_counter).await?; + let c = Comment::from_apub(&c, context, query_url, recursion_counter).await?; response.comments = vec![ blocking(context.pool(), move |conn| { @@ -252,13 +252,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user( return Ok(u); } - let user = User_::from_apub( - &person?, - context, - Some(apub_id.to_owned()), - recursion_counter, - ) - .await?; + let user = User_::from_apub(&person?, context, apub_id.to_owned(), recursion_counter).await?; let user_id = user.id; blocking(context.pool(), move |conn| { @@ -274,13 +268,7 @@ pub(crate) async fn get_or_fetch_and_upsert_user( let person = fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; - let user = User_::from_apub( - &person, - context, - Some(apub_id.to_owned()), - recursion_counter, - ) - .await?; + let user = User_::from_apub(&person, context, apub_id.to_owned(), recursion_counter).await?; Ok(user) } @@ -352,7 +340,7 @@ async fn fetch_remote_community( let group = group?; let community = - Community::from_apub(&group, context, Some(apub_id.to_owned()), recursion_counter).await?; + Community::from_apub(&group, context, apub_id.to_owned(), recursion_counter).await?; // Also add the community moderators too let attributed_to = group.inner.attributed_to().context(location_info!())?; @@ -402,13 +390,13 @@ async fn fetch_remote_community( } for o in outbox_items { let page = PageExt::from_any_base(o)?.context(location_info!())?; + let page_id = page.id_unchecked().context(location_info!())?; - // The post creator may be from a blocked instance, - // if it errors, then continue - match Post::from_apub(&page, context, None, recursion_counter).await { - Ok(post) => post, - Err(_) => continue, - }; + // The post creator may be from a blocked instance, if it errors, then skip it + if check_is_apub_id_valid(page_id).is_err() { + continue; + } + Post::from_apub(&page, context, page_id.to_owned(), recursion_counter).await?; // TODO: we need to send a websocket update here } @@ -436,13 +424,7 @@ pub(crate) async fn get_or_fetch_and_insert_post( debug!("Fetching and creating remote post: {}", post_ap_id); let page = fetch_remote_object::(context.client(), post_ap_id, recursion_counter).await?; - let post = Post::from_apub( - &page, - context, - Some(post_ap_id.to_owned()), - recursion_counter, - ) - .await?; + let post = Post::from_apub(&page, context, post_ap_id.to_owned(), recursion_counter).await?; Ok(post) } @@ -477,7 +459,7 @@ pub(crate) async fn get_or_fetch_and_insert_comment( let comment = Comment::from_apub( &comment, context, - Some(comment_ap_id.to_owned()), + comment_ap_id.to_owned(), recursion_counter, ) .await?; diff --git a/lemmy_apub/src/objects/comment.rs b/lemmy_apub/src/objects/comment.rs index 9ff63cbd..56d75a40 100644 --- a/lemmy_apub/src/objects/comment.rs +++ b/lemmy_apub/src/objects/comment.rs @@ -99,7 +99,7 @@ impl FromApub for Comment { async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { check_object_for_community_or_site_ban(note, context, request_counter).await?; @@ -128,7 +128,7 @@ impl FromApubToForm for CommentForm { async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_actor_id = ¬e diff --git a/lemmy_apub/src/objects/community.rs b/lemmy_apub/src/objects/community.rs index fe05de9e..594a5b5e 100644 --- a/lemmy_apub/src/objects/community.rs +++ b/lemmy_apub/src/objects/community.rs @@ -117,7 +117,7 @@ impl FromApub for Community { async fn from_apub( group: &GroupExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { get_object_from_apub(group, context, expected_domain, request_counter).await @@ -129,7 +129,7 @@ impl FromApubToForm for CommunityForm { async fn from_apub( group: &GroupExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_and_moderator_uris = group.inner.attributed_to().context(location_info!())?; diff --git a/lemmy_apub/src/objects/mod.rs b/lemmy_apub/src/objects/mod.rs index fbe89b09..898c50f3 100644 --- a/lemmy_apub/src/objects/mod.rs +++ b/lemmy_apub/src/objects/mod.rs @@ -38,12 +38,11 @@ pub(crate) trait FromApub { /// /// * `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 + /// * `expected_domain` Domain where the object was received from async fn from_apub( apub: &Self::ApubType, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result where @@ -55,7 +54,7 @@ pub(in crate::objects) trait FromApubToForm { async fn from_apub( apub: &ApubType, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result where @@ -89,17 +88,13 @@ where pub(in crate::objects) fn check_object_domain( apub: &T, - expected_domain: Option, + expected_domain: Url, ) -> Result where T: Base + AsBase, { - let object_id = if let Some(url) = expected_domain { - let domain = url.domain().context(location_info!())?; - apub.id(domain)?.context(location_info!())? - } else { - apub.id_unchecked().context(location_info!())? - }; + let domain = expected_domain.domain().context(location_info!())?; + let object_id = apub.id(domain)?.context(location_info!())?; check_is_apub_id_valid(&object_id)?; Ok(object_id.to_string()) } @@ -180,7 +175,7 @@ pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), L pub(in crate::objects) async fn get_object_from_apub( from: &From, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result where @@ -191,7 +186,7 @@ where let object_id = from.id_unchecked().context(location_info!())?.to_owned(); let domain = object_id.domain().context(location_info!())?; - // if we already have the object in our database, return that directly + // if its a local object, return it directly from the database if Settings::get().hostname == domain { let object = blocking(context.pool(), move |conn| { To::read_from_apub_id(conn, object_id.as_str()) @@ -199,10 +194,7 @@ where .await??; Ok(object) } - // if we dont have it, parse from apub and insert into database - // TODO: this is insecure, a `Like/Post` could result in a non-existent post from a different - // instance being inserted into our database. we should request the object over http in that - // case. this might happen exactly in the case where expected_domain = None, but i'm not sure. + // otherwise parse and insert, assuring that it comes from the right domain else { let to_form = ToForm::from_apub(&from, context, expected_domain, request_counter).await?; diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index 3ca8650d..d34098c5 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -110,7 +110,7 @@ impl FromApub for Post { async fn from_apub( page: &PageExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { check_object_for_community_or_site_ban(page, context, request_counter).await?; @@ -123,7 +123,7 @@ impl FromApubToForm for PostForm { async fn from_apub( page: &PageExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let ext = &page.ext_one; diff --git a/lemmy_apub/src/objects/private_message.rs b/lemmy_apub/src/objects/private_message.rs index 84b5f980..ec8b55e7 100644 --- a/lemmy_apub/src/objects/private_message.rs +++ b/lemmy_apub/src/objects/private_message.rs @@ -71,7 +71,7 @@ impl FromApub for PrivateMessage { async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { get_object_from_apub(note, context, expected_domain, request_counter).await @@ -83,7 +83,7 @@ impl FromApubToForm for PrivateMessageForm { async fn from_apub( note: &NoteExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let creator_actor_id = note diff --git a/lemmy_apub/src/objects/user.rs b/lemmy_apub/src/objects/user.rs index f65df242..18490796 100644 --- a/lemmy_apub/src/objects/user.rs +++ b/lemmy_apub/src/objects/user.rs @@ -95,7 +95,7 @@ impl FromApub for User_ { async fn from_apub( person: &PersonExt, context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, request_counter: &mut i32, ) -> Result { let user_id = person.id_unchecked().context(location_info!())?.to_owned(); @@ -120,7 +120,7 @@ impl FromApubToForm for UserForm { async fn from_apub( person: &PersonExt, _context: &LemmyContext, - expected_domain: Option, + expected_domain: Url, _request_counter: &mut i32, ) -> Result { let avatar = match person.icon() { -- 2.40.1 From ac73470a1721959f92a602c90293e0e67e7f9b10 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 3 Dec 2020 16:49:56 +0100 Subject: [PATCH 13/15] Send out like.object as URL, instead of full object (fixes #1283) --- docs/src/contributing_apub_api_outline.md | 4 +- lemmy_apub/src/activities/receive/comment.rs | 24 +---- .../src/activities/receive/comment_undo.rs | 16 +--- lemmy_apub/src/activities/receive/mod.rs | 25 ----- lemmy_apub/src/activities/receive/post.rs | 23 +---- .../src/activities/receive/post_undo.rs | 16 +--- lemmy_apub/src/activities/send/comment.rs | 12 +-- lemmy_apub/src/activities/send/post.rs | 12 +-- lemmy_apub/src/inbox/receive_for_community.rs | 94 ++++++++++++++----- 9 files changed, 94 insertions(+), 132 deletions(-) diff --git a/docs/src/contributing_apub_api_outline.md b/docs/src/contributing_apub_api_outline.md index 92cdf9c0..74280bd5 100644 --- a/docs/src/contributing_apub_api_outline.md +++ b/docs/src/contributing_apub_api_outline.md @@ -438,7 +438,7 @@ Sent to: Community "cc": [ "https://ds9.lemmy.ml/c/main/" ], - "object": ... + "object": "https://enterprise.lemmy.ml/p/123" } ``` @@ -465,7 +465,7 @@ Sent to: Community "cc": [ "https://ds9.lemmy.ml/c/main/" ], - "object": ... + "object": "https://enterprise.lemmy.ml/p/123" } ``` diff --git a/lemmy_apub/src/activities/receive/comment.rs b/lemmy_apub/src/activities/receive/comment.rs index 1d0260f7..ff0fb819 100644 --- a/lemmy_apub/src/activities/receive/comment.rs +++ b/lemmy_apub/src/activities/receive/comment.rs @@ -1,20 +1,6 @@ -use crate::{ - activities::receive::{get_actor_as_user, get_like_object_id}, - fetcher::get_or_fetch_and_insert_comment, - objects::FromApub, - ActorType, - NoteExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt}; use activitystreams::{ - activity::{ - kind::{DislikeType, LikeType}, - ActorAndObjectRefExt, - Create, - Dislike, - Like, - Remove, - Update, - }, + activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, base::ExtendsExt, }; use anyhow::Context; @@ -113,12 +99,11 @@ pub(crate) async fn receive_update_comment( pub(crate) async fn receive_like_comment( like: Like, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&like, context, request_counter).await?; - let comment_id = get_like_object_id::(&like)?; - let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { @@ -159,12 +144,11 @@ pub(crate) async fn receive_like_comment( pub(crate) async fn receive_dislike_comment( dislike: Dislike, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&dislike, context, request_counter).await?; - let comment_id = get_like_object_id::(&dislike)?; - let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { diff --git a/lemmy_apub/src/activities/receive/comment_undo.rs b/lemmy_apub/src/activities/receive/comment_undo.rs index da924696..2ee8c6ea 100644 --- a/lemmy_apub/src/activities/receive/comment_undo.rs +++ b/lemmy_apub/src/activities/receive/comment_undo.rs @@ -1,11 +1,5 @@ -use crate::{ - activities::receive::{get_actor_as_user, get_like_object_id}, - fetcher::get_or_fetch_and_insert_comment, -}; -use activitystreams::activity::{ - kind::{DislikeType, LikeType}, - *, -}; +use crate::activities::receive::get_actor_as_user; +use activitystreams::activity::{Dislike, Like}; use lemmy_db::{ comment::{Comment, CommentLike}, comment_view::CommentView, @@ -17,12 +11,11 @@ use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_comment( like: &Like, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let comment_id = get_like_object_id::(like)?; - let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let user_id = user.id; @@ -56,12 +49,11 @@ pub(crate) async fn receive_undo_like_comment( pub(crate) async fn receive_undo_dislike_comment( dislike: &Dislike, + comment: Comment, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let comment_id = get_like_object_id::(dislike)?; - let comment = get_or_fetch_and_insert_comment(&comment_id, context, request_counter).await?; let comment_id = comment.id; let user_id = user.id; diff --git a/lemmy_apub/src/activities/receive/mod.rs b/lemmy_apub/src/activities/receive/mod.rs index d67f12fa..1f17fe9f 100644 --- a/lemmy_apub/src/activities/receive/mod.rs +++ b/lemmy_apub/src/activities/receive/mod.rs @@ -79,28 +79,3 @@ where Ok(()) } - -pub(in crate::activities::receive) fn get_like_object_id( - like_or_dislike: &Activity, -) -> Result -where - Activity: ActorAndObjectRefExt, -{ - // For backwards compatibility with older Lemmy versions where like.object contains a full - // post/comment. This can be removed after some time, using - // `activity.oject().as_single_xsd_any_uri()` instead. - let object = like_or_dislike.object(); - if let Some(xsd_uri) = object.as_single_xsd_any_uri() { - Ok(xsd_uri.to_owned()) - } else { - Ok( - object - .to_owned() - .one() - .context(location_info!())? - .id() - .context(location_info!())? - .to_owned(), - ) - } -} diff --git a/lemmy_apub/src/activities/receive/post.rs b/lemmy_apub/src/activities/receive/post.rs index 04d83d37..0bbf1eaf 100644 --- a/lemmy_apub/src/activities/receive/post.rs +++ b/lemmy_apub/src/activities/receive/post.rs @@ -1,19 +1,6 @@ -use crate::{ - activities::receive::{get_actor_as_user, get_like_object_id}, - fetcher::get_or_fetch_and_insert_post, - objects::FromApub, - ActorType, - PageExt, -}; +use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt}; use activitystreams::{ - activity::{ - kind::{DislikeType, LikeType}, - Create, - Dislike, - Like, - Remove, - Update, - }, + activity::{Create, Dislike, Like, Remove, Update}, prelude::*, }; use anyhow::Context; @@ -86,12 +73,11 @@ pub(crate) async fn receive_update_post( pub(crate) async fn receive_like_post( like: Like, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&like, context, request_counter).await?; - let post_id = get_like_object_id::(&like)?; - let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { @@ -125,12 +111,11 @@ pub(crate) async fn receive_like_post( pub(crate) async fn receive_dislike_post( dislike: Dislike, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(&dislike, context, request_counter).await?; - let post_id = get_like_object_id::(&dislike)?; - let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { diff --git a/lemmy_apub/src/activities/receive/post_undo.rs b/lemmy_apub/src/activities/receive/post_undo.rs index cf2f447b..bcbb7fee 100644 --- a/lemmy_apub/src/activities/receive/post_undo.rs +++ b/lemmy_apub/src/activities/receive/post_undo.rs @@ -1,11 +1,5 @@ -use crate::{ - activities::receive::{get_actor_as_user, get_like_object_id}, - fetcher::get_or_fetch_and_insert_post, -}; -use activitystreams::activity::{ - kind::{DislikeType, LikeType}, - *, -}; +use crate::activities::receive::get_actor_as_user; +use activitystreams::activity::{Dislike, Like}; use lemmy_db::{ post::{Post, PostLike}, post_view::PostView, @@ -17,12 +11,11 @@ use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; pub(crate) async fn receive_undo_like_post( like: &Like, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(like, context, request_counter).await?; - let post_id = get_like_object_id::(&like)?; - let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let user_id = user.id; @@ -50,12 +43,11 @@ pub(crate) async fn receive_undo_like_post( pub(crate) async fn receive_undo_dislike_post( dislike: &Dislike, + post: Post, context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { let user = get_actor_as_user(dislike, context, request_counter).await?; - let post_id = get_like_object_id::(&dislike)?; - let post = get_or_fetch_and_insert_post(&post_id, context, request_counter).await?; let post_id = post.id; let user_id = user.id; diff --git a/lemmy_apub/src/activities/send/comment.rs b/lemmy_apub/src/activities/send/comment.rs index 4415211f..744a1cdd 100644 --- a/lemmy_apub/src/activities/send/comment.rs +++ b/lemmy_apub/src/activities/send/comment.rs @@ -218,8 +218,6 @@ impl ApubObjectType for Comment { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Comment { async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -229,7 +227,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) @@ -241,8 +239,6 @@ impl ApubLikeableType for Comment { } async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -252,7 +248,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut dislike = Dislike::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); dislike .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) @@ -268,8 +264,6 @@ impl ApubLikeableType for Comment { creator: &User_, context: &LemmyContext, ) -> Result<(), LemmyError> { - let note = self.to_apub(context.pool()).await?; - let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -279,7 +273,7 @@ impl ApubLikeableType for Comment { }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), note.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) diff --git a/lemmy_apub/src/activities/send/post.rs b/lemmy_apub/src/activities/send/post.rs index d5ff56ac..f6eabb04 100644 --- a/lemmy_apub/src/activities/send/post.rs +++ b/lemmy_apub/src/activities/send/post.rs @@ -167,15 +167,13 @@ impl ApubObjectType for Post { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Post { async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) @@ -187,15 +185,13 @@ impl ApubLikeableType for Post { } async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut dislike = Dislike::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut dislike = Dislike::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); dislike .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DislikeType::Dislike)?) @@ -211,15 +207,13 @@ impl ApubLikeableType for Post { creator: &User_, context: &LemmyContext, ) -> Result<(), LemmyError> { - let page = self.to_apub(context.pool()).await?; - let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) }) .await??; - let mut like = Like::new(creator.actor_id.to_owned(), page.into_any_base()?); + let mut like = Like::new(creator.actor_id.to_owned(), Url::parse(&self.ap_id)?); like .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) diff --git a/lemmy_apub/src/inbox/receive_for_community.rs b/lemmy_apub/src/inbox/receive_for_community.rs index 710cf17b..4eaf3979 100644 --- a/lemmy_apub/src/inbox/receive_for_community.rs +++ b/lemmy_apub/src/inbox/receive_for_community.rs @@ -31,6 +31,7 @@ use crate::{ receive_unhandled_activity, verify_activity_domains_valid, }, + fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post}, inbox::is_addressed_to_public, }; use activitystreams::{ @@ -96,10 +97,12 @@ pub(in crate::inbox) async fn receive_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - match like.object().as_single_kind_str() { - Some("Page") => receive_like_post(like, context, request_counter).await, - Some("Note") => receive_like_comment(like, context, request_counter).await, - _ => receive_unhandled_activity(like), + let object_id = get_like_object_id(&like)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => receive_like_post(like, post, context, request_counter).await, + PostOrComment::Comment(comment) => { + receive_like_comment(like, comment, context, request_counter).await + } } } @@ -122,10 +125,14 @@ pub(in crate::inbox) async fn receive_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - match dislike.object().as_single_kind_str() { - Some("Page") => receive_dislike_post(dislike, context, request_counter).await, - Some("Note") => receive_dislike_comment(dislike, context, request_counter).await, - _ => receive_unhandled_activity(dislike), + let object_id = get_like_object_id(&dislike)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_dislike_post(dislike, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_dislike_comment(dislike, comment, context, request_counter).await + } } } @@ -275,14 +282,14 @@ pub(in crate::inbox) async fn receive_undo_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - let type_ = like - .object() - .as_single_kind_str() - .context(location_info!())?; - match type_ { - "Note" => receive_undo_like_comment(&like, context, request_counter).await, - "Page" => receive_undo_like_post(&like, context, request_counter).await, - _ => receive_unhandled_activity(like), + let object_id = get_like_object_id(&like)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_undo_like_post(&like, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_undo_like_comment(&like, comment, context, request_counter).await + } } } @@ -298,14 +305,14 @@ pub(in crate::inbox) async fn receive_undo_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - let type_ = dislike - .object() - .as_single_kind_str() - .context(location_info!())?; - match type_ { - "Note" => receive_undo_dislike_comment(&dislike, context, request_counter).await, - "Page" => receive_undo_dislike_post(&dislike, context, request_counter).await, - _ => receive_unhandled_activity(dislike), + let object_id = get_like_object_id(&dislike)?; + match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { + PostOrComment::Post(post) => { + receive_undo_dislike_post(&dislike, post, context, request_counter).await + } + PostOrComment::Comment(comment) => { + receive_undo_dislike_comment(&dislike, comment, context, request_counter).await + } } } @@ -341,3 +348,42 @@ async fn find_post_or_comment_by_id( return Err(NotFound.into()); } + +async fn fetch_post_or_comment_by_id( + apub_id: &Url, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result { + if let Ok(post) = get_or_fetch_and_insert_post(apub_id, context, request_counter).await { + return Ok(PostOrComment::Post(post)); + } + + if let Ok(comment) = get_or_fetch_and_insert_comment(apub_id, context, request_counter).await { + return Ok(PostOrComment::Comment(comment)); + } + + return Err(NotFound.into()); +} + +fn get_like_object_id(like_or_dislike: &Activity) -> Result +where + Activity: ActorAndObjectRefExt, +{ + // For backwards compatibility with older Lemmy versions where like.object contains a full + // post/comment. This can be removed after some time, using + // `activity.oject().as_single_xsd_any_uri()` instead. + let object = like_or_dislike.object(); + if let Some(xsd_uri) = object.as_single_xsd_any_uri() { + Ok(xsd_uri.to_owned()) + } else { + Ok( + object + .to_owned() + .one() + .context(location_info!())? + .id() + .context(location_info!())? + .to_owned(), + ) + } +} -- 2.40.1 From a90adb858294227272fb42fc01d29e876e3fa4ec Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Fri, 4 Dec 2020 14:16:38 +0100 Subject: [PATCH 14/15] add todo --- lemmy_apub/src/inbox/receive_for_community.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lemmy_apub/src/inbox/receive_for_community.rs b/lemmy_apub/src/inbox/receive_for_community.rs index 4eaf3979..eaad6b1c 100644 --- a/lemmy_apub/src/inbox/receive_for_community.rs +++ b/lemmy_apub/src/inbox/receive_for_community.rs @@ -369,9 +369,9 @@ fn get_like_object_id(like_or_dislike: &Activity) -> Result Date: Mon, 7 Dec 2020 13:40:39 +0100 Subject: [PATCH 15/15] Remove logging to find bug (yerbamate.ml/LemmyNet/lemmy/pulls/146) --- Cargo.lock | 1 - lemmy_apub/Cargo.toml | 1 - lemmy_apub/src/objects/post.rs | 11 ----------- 3 files changed, 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf741d68..7823e9fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,6 @@ dependencies = [ "async-trait", "awc", "background-jobs", - "backtrace", "base64 0.13.0", "bcrypt", "chrono", diff --git a/lemmy_apub/Cargo.toml b/lemmy_apub/Cargo.toml index 7e8f792a..5610ed69 100644 --- a/lemmy_apub/Cargo.toml +++ b/lemmy_apub/Cargo.toml @@ -46,4 +46,3 @@ anyhow = "1.0" thiserror = "1.0" background-jobs = " 0.8" reqwest = { version = "0.10", features = ["json"] } -backtrace = "0.3" diff --git a/lemmy_apub/src/objects/post.rs b/lemmy_apub/src/objects/post.rs index d34098c5..39b74997 100644 --- a/lemmy_apub/src/objects/post.rs +++ b/lemmy_apub/src/objects/post.rs @@ -20,7 +20,6 @@ use activitystreams::{ }; use activitystreams_ext::Ext1; use anyhow::Context; -use backtrace::Backtrace; use lemmy_db::{ community::Community, post::{Post, PostForm}, @@ -36,7 +35,6 @@ use lemmy_utils::{ LemmyError, }; use lemmy_websocket::LemmyContext; -use log::error; use url::Url; #[async_trait::async_trait(?Send)] @@ -148,15 +146,6 @@ impl FromApubToForm for PostForm { let community = get_or_fetch_and_upsert_community(community_actor_id, context, request_counter).await?; - if community.local && creator.local { - let page_id = page.id_unchecked().context(location_info!())?; - let bt = Backtrace::new(); - error!( - "Lemmy is parsing a local post as remote, page id: {}, stack trace: {:?}", - page_id, bt - ); - } - let thumbnail_url = match &page.inner.image() { Some(any_image) => Image::from_any_base( any_image -- 2.40.1