From 6746d973a13f1d1643496c54818e225580b1256d Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Thu, 5 Nov 2020 13:15:19 +0100 Subject: [PATCH] Fix federation of community deletion/removal (fixes #1253) --- lemmy_api/src/community.rs | 8 +++--- lemmy_apub/src/activities/send/community.rs | 31 ++++++++------------- lemmy_apub/src/activities/send/user.rs | 16 +++-------- lemmy_apub/src/fetcher.rs | 25 ++++++++++++----- lemmy_apub/src/lib.rs | 12 +++----- 5 files changed, 41 insertions(+), 51 deletions(-) diff --git a/lemmy_api/src/community.rs b/lemmy_api/src/community.rs index 4149053f6..4c9d769ba 100644 --- a/lemmy_api/src/community.rs +++ b/lemmy_api/src/community.rs @@ -327,9 +327,9 @@ impl Perform for DeleteCommunity { // Send apub messages if deleted { - updated_community.send_delete(&user, context).await?; + updated_community.send_delete(context).await?; } else { - updated_community.send_undo_delete(&user, context).await?; + updated_community.send_undo_delete(context).await?; } let edit_id = data.edit_id; @@ -395,9 +395,9 @@ impl Perform for RemoveCommunity { // Apub messages if removed { - updated_community.send_remove(&user, context).await?; + updated_community.send_remove(context).await?; } else { - updated_community.send_undo_remove(&user, context).await?; + updated_community.send_undo_remove(context).await?; } let edit_id = data.edit_id; diff --git a/lemmy_apub/src/activities/send/community.rs b/lemmy_apub/src/activities/send/community.rs index 446ce6f34..cdcc96707 100644 --- a/lemmy_apub/src/activities/send/community.rs +++ b/lemmy_apub/src/activities/send/community.rs @@ -4,7 +4,6 @@ use crate::{ check_is_apub_id_valid, fetcher::get_or_fetch_and_upsert_user, ActorType, - ToApub, }; use activitystreams::{ activity::{ @@ -23,7 +22,7 @@ use activitystreams::{ }; use anyhow::Context; use itertools::Itertools; -use lemmy_db::{community::Community, community_view::CommunityFollowerView, user::User_, DbPool}; +use lemmy_db::{community::Community, community_view::CommunityFollowerView, DbPool}; use lemmy_structs::blocking; use lemmy_utils::{location_info, settings::Settings, LemmyError}; use lemmy_websocket::LemmyContext; @@ -85,10 +84,8 @@ impl ActorType for Community { } /// If the creator of a community deletes the community, send this to all followers. - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let group = self.to_apub(context.pool()).await?; - - let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?); + async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> { + let mut delete = Delete::new(self.actor_id()?, self.actor_id()?); delete .set_context(activitystreams::context()) .set_id(generate_activity_id(DeleteType::Delete)?) @@ -100,21 +97,15 @@ impl ActorType for Community { } /// If the creator of a community reverts the deletion of a community, send this to all followers. - async fn send_undo_delete( - &self, - creator: &User_, - context: &LemmyContext, - ) -> Result<(), LemmyError> { - let group = self.to_apub(context.pool()).await?; - - let mut delete = Delete::new(creator.actor_id.to_owned(), group.into_any_base()?); + async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError> { + let mut delete = Delete::new(self.actor_id()?, self.actor_id()?); delete .set_context(activitystreams::context()) .set_id(generate_activity_id(DeleteType::Delete)?) .set_to(public()) .set_many_ccs(vec![self.get_followers_url()?]); - let mut undo = Undo::new(creator.actor_id.to_owned(), delete.into_any_base()?); + let mut undo = Undo::new(self.actor_id()?, delete.into_any_base()?); undo .set_context(activitystreams::context()) .set_id(generate_activity_id(UndoType::Undo)?) @@ -126,8 +117,8 @@ impl ActorType for Community { } /// If an admin removes a community, send this to all followers. - async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?); + async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> { + let mut remove = Remove::new(self.actor_id()?, self.actor_id()?); remove .set_context(activitystreams::context()) .set_id(generate_activity_id(RemoveType::Remove)?) @@ -139,8 +130,8 @@ impl ActorType for Community { } /// If an admin reverts the removal of a community, send this to all followers. - async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { - let mut remove = Remove::new(mod_.actor_id.to_owned(), self.actor_id()?); + async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError> { + let mut remove = Remove::new(self.actor_id()?, self.actor_id()?); remove .set_context(activitystreams::context()) .set_id(generate_activity_id(RemoveType::Remove)?) @@ -148,7 +139,7 @@ impl ActorType for Community { .set_many_ccs(vec![self.get_followers_url()?]); // Undo that fake activity - let mut undo = Undo::new(mod_.actor_id.to_owned(), remove.into_any_base()?); + let mut undo = Undo::new(self.actor_id()?, remove.into_any_base()?); undo .set_context(activitystreams::context()) .set_id(generate_activity_id(LikeType::Like)?) diff --git a/lemmy_apub/src/activities/send/user.rs b/lemmy_apub/src/activities/send/user.rs index c4d287a56..bd791e5e3 100644 --- a/lemmy_apub/src/activities/send/user.rs +++ b/lemmy_apub/src/activities/send/user.rs @@ -94,27 +94,19 @@ impl ActorType for User_ { unimplemented!() } - async fn send_delete(&self, _creator: &User_, _context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_delete(&self, _context: &LemmyContext) -> Result<(), LemmyError> { unimplemented!() } - async fn send_undo_delete( - &self, - _creator: &User_, - _context: &LemmyContext, - ) -> Result<(), LemmyError> { + async fn send_undo_delete(&self, _context: &LemmyContext) -> Result<(), LemmyError> { unimplemented!() } - async fn send_remove(&self, _creator: &User_, _context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_remove(&self, _context: &LemmyContext) -> Result<(), LemmyError> { unimplemented!() } - async fn send_undo_remove( - &self, - _creator: &User_, - _context: &LemmyContext, - ) -> Result<(), LemmyError> { + async fn send_undo_remove(&self, _context: &LemmyContext) -> Result<(), LemmyError> { unimplemented!() } diff --git a/lemmy_apub/src/fetcher.rs b/lemmy_apub/src/fetcher.rs index 43466a0f5..ff3b03d34 100644 --- a/lemmy_apub/src/fetcher.rs +++ b/lemmy_apub/src/fetcher.rs @@ -251,10 +251,14 @@ pub(crate) async fn get_or_fetch_and_upsert_user( Ok(u) if !u.local && should_refetch_actor(u.last_refreshed_at) => { debug!("Fetching and updating from remote user: {}", apub_id); let person = - fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; + fetch_remote_object::(context.client(), apub_id, recursion_counter).await; + // If fetching failed, return the existing data. + if person.is_err() { + return Ok(u); + } let mut uf = UserForm::from_apub( - &person, + &person?, context, Some(apub_id.to_owned()), recursion_counter, @@ -320,7 +324,7 @@ pub(crate) async fn get_or_fetch_and_upsert_community( match community { Ok(c) if !c.local && should_refetch_actor(c.last_refreshed_at) => { debug!("Fetching and updating from remote community: {}", apub_id); - fetch_remote_community(apub_id, context, Some(c.id), recursion_counter).await + fetch_remote_community(apub_id, context, Some(c), recursion_counter).await } Ok(c) => Ok(c), Err(NotFound {}) => { @@ -331,17 +335,24 @@ pub(crate) async fn get_or_fetch_and_upsert_community( } } -/// Request a community by apub ID from a remote instance, including moderators. If `community_id`, +/// Request a community by apub ID from a remote instance, including moderators. If `old_community`, /// is set, this is an update for a community which is already known locally. If not, we don't know /// the community yet and also pull the outbox, to get some initial posts. async fn fetch_remote_community( apub_id: &Url, context: &LemmyContext, - community_id: Option, + old_community: Option, recursion_counter: &mut i32, ) -> Result { - let group = fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; + let group = fetch_remote_object::(context.client(), apub_id, recursion_counter).await; + // If fetching failed, return the existing data. + if let Some(ref c) = old_community { + if group.is_err() { + return Ok(c.to_owned()); + } + } + 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??; @@ -364,7 +375,7 @@ async fn fetch_remote_community( } // TODO: need to make this work to update mods of existing communities - if community_id.is_none() { + if old_community.is_none() { let community_id = community.id; blocking(context.pool(), move |conn| { for mod_ in creator_and_moderators { diff --git a/lemmy_apub/src/lib.rs b/lemmy_apub/src/lib.rs index 4449c94f4..e7410ee25 100644 --- a/lemmy_apub/src/lib.rs +++ b/lemmy_apub/src/lib.rs @@ -189,15 +189,11 @@ pub trait ActorType { context: &LemmyContext, ) -> Result<(), LemmyError>; - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_delete( - &self, - creator: &User_, - context: &LemmyContext, - ) -> Result<(), LemmyError>; + async fn send_delete(&self, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_undo_delete(&self, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_undo_remove(&self, context: &LemmyContext) -> Result<(), LemmyError>; async fn send_announce( &self,