diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index c12212e9f..a13896fdf 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -160,6 +160,7 @@ impl Perform for BanFromCommunity { }) .await? .ok(); + community .send_block_user(&local_user_view.person, banned_person, context) .await?; diff --git a/crates/apub/src/activities/send/comment.rs b/crates/apub/src/activities/send/comment.rs index 76371b997..b27255755 100644 --- a/crates/apub/src/activities/send/comment.rs +++ b/crates/apub/src/activities/send/comment.rs @@ -71,7 +71,7 @@ impl ApubObjectType for Comment { // Set the mention tags .set_many_tags(maa.get_tags()?); - send_to_community(create.clone(), &creator, &community, context).await?; + send_to_community(create.clone(), &creator, &community, None, context).await?; send_comment_mentions(&creator, maa.inboxes, create, context).await?; Ok(()) } @@ -104,7 +104,7 @@ impl ApubObjectType for Comment { // Set the mention tags .set_many_tags(maa.get_tags()?); - send_to_community(update.clone(), &creator, &community, context).await?; + send_to_community(update.clone(), &creator, &community, None, context).await?; send_comment_mentions(&creator, maa.inboxes, update, context).await?; Ok(()) } @@ -129,7 +129,7 @@ impl ApubObjectType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(delete, &creator, &community, context).await?; + send_to_community(delete, &creator, &community, None, context).await?; Ok(()) } @@ -169,7 +169,7 @@ impl ApubObjectType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, &creator, &community, context).await?; + send_to_community(undo, &creator, &community, None, context).await?; Ok(()) } @@ -193,7 +193,7 @@ impl ApubObjectType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(remove, &mod_, &community, context).await?; + send_to_community(remove, &mod_, &community, None, context).await?; Ok(()) } @@ -233,7 +233,7 @@ impl ApubObjectType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, &mod_, &community, context).await?; + send_to_community(undo, &mod_, &community, None, context).await?; Ok(()) } } @@ -260,7 +260,7 @@ impl ApubLikeableType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(like, &creator, &community, context).await?; + send_to_community(like, &creator, &community, None, context).await?; Ok(()) } @@ -284,7 +284,7 @@ impl ApubLikeableType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(dislike, &creator, &community, context).await?; + send_to_community(dislike, &creator, &community, None, context).await?; Ok(()) } @@ -323,7 +323,7 @@ impl ApubLikeableType for Comment { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, &creator, &community, context).await?; + send_to_community(undo, &creator, &community, None, context).await?; Ok(()) } } diff --git a/crates/apub/src/activities/send/community.rs b/crates/apub/src/activities/send/community.rs index ba36de503..5b93cbb2b 100644 --- a/crates/apub/src/activities/send/community.rs +++ b/crates/apub/src/activities/send/community.rs @@ -3,7 +3,7 @@ use crate::{ activity_queue::{send_activity_single_dest, send_to_community, send_to_community_followers}, check_is_apub_id_valid, extensions::context::lemmy_context, - fetcher::person::get_or_fetch_and_upsert_person, + fetcher::{get_or_fetch_and_upsert_actor, person::get_or_fetch_and_upsert_person}, generate_moderators_url, insert_activity, ActorType, @@ -72,6 +72,10 @@ impl ActorType for Community { #[async_trait::async_trait(?Send)] impl CommunityType for Community { + fn followers_url(&self) -> Url { + self.followers_url.clone().into_inner() + } + /// As a local community, accept the follow request from a remote person. async fn send_accept_follow( &self, @@ -104,9 +108,9 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DeleteType::Delete)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); - send_to_community_followers(delete, self, context).await?; + send_to_community_followers(delete, self, None, context).await?; Ok(()) } @@ -117,16 +121,16 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(DeleteType::Delete)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?); undo .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(UndoType::Undo)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); - send_to_community_followers(undo, self, context).await?; + send_to_community_followers(undo, self, None, context).await?; Ok(()) } @@ -137,9 +141,9 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(RemoveType::Remove)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); - send_to_community_followers(remove, self, context).await?; + send_to_community_followers(remove, self, None, context).await?; Ok(()) } @@ -150,7 +154,7 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(RemoveType::Remove)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); // Undo that fake activity let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?); @@ -158,9 +162,9 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(LikeType::Like)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(vec![self.followers_url()]); - send_to_community_followers(undo, self, context).await?; + send_to_community_followers(undo, self, None, context).await?; Ok(()) } @@ -170,9 +174,13 @@ impl CommunityType for Community { /// If we are announcing a local activity, it hasn't been stored in the database yet, and we need /// to do it here, so that it can be fetched by ID. Remote activities are inserted into DB in the /// inbox. + /// + /// If the `object` of the announced activity is an actor, the actor ID needs to be passed as + /// `object_actor`, so that the announce can be delivered to that user. async fn send_announce( &self, activity: AnyBase, + object_actor: Option, context: &LemmyContext, ) -> Result<(), LemmyError> { let inner_id = activity.id().context(location_info!())?; @@ -180,14 +188,27 @@ impl CommunityType for Community { insert_activity(inner_id, activity.clone(), true, false, context.pool()).await?; } + let mut ccs = vec![self.followers_url()]; + let mut object_actor_inbox: Option = None; + if let Some(actor_id) = object_actor { + // Ignore errors, maybe its not actually an actor + // TODO: should pass the actual request counter in, but that seems complicated + let actor = get_or_fetch_and_upsert_actor(&actor_id, context, &mut 0) + .await + .ok(); + if let Some(actor) = actor { + ccs.push(actor_id); + object_actor_inbox = Some(actor.get_shared_inbox_or_inbox_url()); + } + } let mut announce = Announce::new(self.actor_id(), activity); announce .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(AnnounceType::Announce)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); + .set_many_ccs(ccs); - send_to_community_followers(announce, self, context).await?; + send_to_community_followers(announce, self, object_actor_inbox, context).await?; Ok(()) } @@ -227,7 +248,7 @@ impl CommunityType for Community { .set_many_ccs(vec![self.actor_id()]) .set_target(generate_moderators_url(&self.actor_id)?.into_inner()); - send_to_community(add, actor, self, context).await?; + send_to_community(add, actor, self, Some(added_mod.actor_id()), context).await?; Ok(()) } @@ -245,11 +266,10 @@ impl CommunityType for Community { .set_many_ccs(vec![self.actor_id()]) .set_target(generate_moderators_url(&self.actor_id)?.into_inner()); - send_to_community(remove, &actor, self, context).await?; + send_to_community(remove, &actor, self, Some(removed_mod.actor_id()), context).await?; Ok(()) } - // / TODO: also need to implement the Undo for this async fn send_block_user( &self, actor: &Person, @@ -263,17 +283,17 @@ impl CommunityType for Community { .set_to(public()) .set_many_ccs(vec![self.actor_id()]); - send_to_community(block, &actor, self, context).await?; + send_to_community(block, &actor, self, Some(blocked_user.actor_id()), context).await?; Ok(()) } async fn send_undo_block_user( &self, actor: &Person, - blocked_user: Person, + unblocked_user: Person, context: &LemmyContext, ) -> Result<(), LemmyError> { - let mut block = Block::new(actor.actor_id(), blocked_user.actor_id()); + let mut block = Block::new(actor.actor_id(), unblocked_user.actor_id()); block .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(BlockType::Block)?) @@ -286,8 +306,9 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(UndoType::Undo)?) .set_to(public()) - .set_many_ccs(vec![self.followers_url.clone().into_inner()]); - send_to_community(undo, &actor, self, context).await?; + .set_many_ccs(vec![self.actor_id()]); + + send_to_community(undo, &actor, self, Some(unblocked_user.actor_id()), context).await?; Ok(()) } } diff --git a/crates/apub/src/activities/send/post.rs b/crates/apub/src/activities/send/post.rs index 9f8be1e1e..0af7369ac 100644 --- a/crates/apub/src/activities/send/post.rs +++ b/crates/apub/src/activities/send/post.rs @@ -49,7 +49,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(create, creator, &community, context).await?; + send_to_community(create, creator, &community, None, context).await?; Ok(()) } @@ -73,7 +73,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(update, creator, &community, context).await?; + send_to_community(update, creator, &community, None, context).await?; Ok(()) } @@ -94,7 +94,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(delete, creator, &community, context).await?; + send_to_community(delete, creator, &community, None, context).await?; Ok(()) } @@ -130,7 +130,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, creator, &community, context).await?; + send_to_community(undo, creator, &community, None, context).await?; Ok(()) } @@ -151,7 +151,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(remove, mod_, &community, context).await?; + send_to_community(remove, mod_, &community, None, context).await?; Ok(()) } @@ -187,7 +187,7 @@ impl ApubObjectType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, mod_, &community, context).await?; + send_to_community(undo, mod_, &community, None, context).await?; Ok(()) } } @@ -211,7 +211,7 @@ impl ApubLikeableType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(like, &creator, &community, context).await?; + send_to_community(like, &creator, &community, None, context).await?; Ok(()) } @@ -232,7 +232,7 @@ impl ApubLikeableType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(dislike, &creator, &community, context).await?; + send_to_community(dislike, &creator, &community, None, context).await?; Ok(()) } @@ -268,7 +268,7 @@ impl ApubLikeableType for Post { .set_to(public()) .set_many_ccs(vec![community.actor_id()]); - send_to_community(undo, &creator, &community, context).await?; + send_to_community(undo, &creator, &community, None, context).await?; Ok(()) } } diff --git a/crates/apub/src/activity_queue.rs b/crates/apub/src/activity_queue.rs index b1913b4b1..924b3dd61 100644 --- a/crates/apub/src/activity_queue.rs +++ b/crates/apub/src/activity_queue.rs @@ -21,7 +21,6 @@ use background_jobs::{ WorkerConfig, }; use itertools::Itertools; -use lemmy_db_queries::DbPool; use lemmy_db_schema::source::{community::Community, person::Person}; use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; @@ -53,16 +52,7 @@ where &activity.id_unchecked(), &inbox ); - send_activity_internal( - context.activity_queue(), - activity, - creator, - vec![inbox], - context.pool(), - true, - true, - ) - .await?; + send_activity_internal(context, activity, creator, vec![inbox], true, true).await?; } Ok(()) @@ -72,11 +62,11 @@ where /// /// * `activity` the apub activity to send /// * `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 +/// * `extra_inbox` actor inbox which should receive the activity, in addition to followers pub(crate) async fn send_to_community_followers( activity: T, community: &Community, + extra_inbox: Option, context: &LemmyContext, ) -> Result<(), LemmyError> where @@ -84,31 +74,25 @@ where Kind: Serialize, >::Error: From + Send + Sync + 'static, { - let follower_inboxes: Vec = community - .get_follower_inboxes(context.pool()) - .await? - .iter() - .unique() - .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname())) - .filter(|inbox| check_is_apub_id_valid(inbox).is_ok()) - .map(|inbox| inbox.to_owned()) - .collect(); + let extra_inbox: Vec = extra_inbox.into_iter().collect(); + let follower_inboxes: Vec = vec![ + community.get_follower_inboxes(context.pool()).await?, + extra_inbox, + ] + .iter() + .flatten() + .unique() + .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname())) + .filter(|inbox| check_is_apub_id_valid(inbox).is_ok()) + .map(|inbox| inbox.to_owned()) + .collect(); debug!( "Sending activity {:?} to followers of {}", &activity.id_unchecked().map(|i| i.to_string()), &community.actor_id ); - send_activity_internal( - context.activity_queue(), - activity, - community, - follower_inboxes, - context.pool(), - true, - false, - ) - .await?; + send_activity_internal(context, activity, community, follower_inboxes, true, false).await?; Ok(()) } @@ -118,11 +102,14 @@ where /// * `activity` the activity to send /// * `creator` the creator of the activity /// * `community` the destination community +/// * `object_actor` if the object of the activity is an actor, it should be passed here so it can +/// be sent directly to the actor /// pub(crate) async fn send_to_community( activity: T, creator: &Person, community: &Community, + object_actor: Option, context: &LemmyContext, ) -> Result<(), LemmyError> where @@ -133,7 +120,7 @@ where // if this is a local community, we need to do an announce from the community instead if community.local { community - .send_announce(activity.into_any_base()?, context) + .send_announce(activity.into_any_base()?, object_actor, context) .await?; } else { let inbox = community.get_shared_inbox_or_inbox_url(); @@ -143,16 +130,8 @@ where &activity.id_unchecked(), &community.actor_id ); - send_activity_internal( - context.activity_queue(), - activity, - creator, - vec![inbox], - context.pool(), - true, - false, - ) - .await?; + // dont send to object_actor here, as that is responsibility of the community itself + send_activity_internal(context, activity, creator, vec![inbox], true, false).await?; } Ok(()) @@ -185,12 +164,7 @@ where .map(|i| i.to_owned()) .collect(); send_activity_internal( - context.activity_queue(), - activity, - creator, - mentions, - context.pool(), - false, // Don't create a new DB row + context, activity, creator, mentions, false, // Don't create a new DB row false, ) .await?; @@ -203,11 +177,10 @@ where /// The caller of this function needs to remove any blocked domains from `to`, /// using `check_is_apub_id_valid()`. async fn send_activity_internal( - activity_sender: &QueueHandle, + context: &LemmyContext, activity: T, actor: &dyn ActorType, inboxes: Vec, - pool: &DbPool, insert_into_db: bool, sensitive: bool, ) -> Result<(), LemmyError> @@ -234,7 +207,7 @@ where // might send the same ap_id if insert_into_db { let id = activity.id().context(location_info!())?; - insert_activity(id, activity.clone(), true, sensitive, pool).await?; + insert_activity(id, activity.clone(), true, sensitive, context.pool()).await?; } for i in inboxes { @@ -247,7 +220,7 @@ where if env::var("LEMMY_TEST_SEND_SYNC").is_ok() { do_send(message, &Client::default()).await?; } else { - activity_sender.queue::(message)?; + context.activity_queue.queue::(message)?; } } diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 875fd507b..37e959014 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -191,6 +191,7 @@ pub trait ActorType { #[async_trait::async_trait(?Send)] pub trait CommunityType { + fn followers_url(&self) -> Url; async fn get_follower_inboxes(&self, pool: &DbPool) -> Result, LemmyError>; async fn send_accept_follow( &self, @@ -207,6 +208,7 @@ pub trait CommunityType { async fn send_announce( &self, activity: AnyBase, + object: Option, context: &LemmyContext, ) -> Result<(), LemmyError>; diff --git a/crates/apub_receive/src/inbox/community_inbox.rs b/crates/apub_receive/src/inbox/community_inbox.rs index a0763bc56..f22f3fe05 100644 --- a/crates/apub_receive/src/inbox/community_inbox.rs +++ b/crates/apub_receive/src/inbox/community_inbox.rs @@ -241,8 +241,9 @@ pub(crate) async fn community_receive_message( if do_announce { // Check again that the activity is public, just to be sure verify_is_addressed_to_public(&activity)?; + let object_actor = activity.object().clone().single_xsd_any_uri(); to_community - .send_announce(activity.into_any_base()?, context) + .send_announce(activity.into_any_base()?, object_actor, context) .await?; } diff --git a/crates/apub_receive/src/inbox/receive_for_community.rs b/crates/apub_receive/src/inbox/receive_for_community.rs index 321a762af..2fcd17af0 100644 --- a/crates/apub_receive/src/inbox/receive_for_community.rs +++ b/crates/apub_receive/src/inbox/receive_for_community.rs @@ -260,7 +260,13 @@ pub(in crate::inbox) async fn receive_remove_for_community( CommunityModerator::leave(conn, &form) }) .await??; - community.send_announce(remove_any_base, context).await?; + community + .send_announce( + remove_any_base, + remove.object().clone().single_xsd_any_uri(), + context, + ) + .await?; // TODO: send websocket notification about removed mod Ok(()) } @@ -446,7 +452,13 @@ pub(in crate::inbox) async fn receive_add_for_community( .await??; } if community.local { - community.send_announce(add_any_base, context).await?; + community + .send_announce( + add_any_base, + add.object().clone().single_xsd_any_uri(), + context, + ) + .await?; } // TODO: send websocket notification about added mod Ok(()) diff --git a/docker/dev/volume_mount.dockerfile b/docker/dev/volume_mount.dockerfile index 0cb036247..38e019f7f 100644 --- a/docker/dev/volume_mount.dockerfile +++ b/docker/dev/volume_mount.dockerfile @@ -24,7 +24,6 @@ RUN apt-get update -y RUN apt-get install -y libpq-dev espeak # Copy resources -COPY config/defaults.hjson /config/defaults.hjson COPY --from=rust /app/lemmy_server /app/lemmy EXPOSE 8536 diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml index ee6e2d27d..b2c9fae7f 100644 --- a/docker/federation/docker-compose.yml +++ b/docker/federation/docker-compose.yml @@ -29,7 +29,7 @@ services: - ./volumes/pictrs_alpha:/mnt lemmy-alpha-ui: - image: dessalines/lemmy-ui:0.10.2 + image: dessalines/lemmy-ui:0.10.3 environment: - LEMMY_INTERNAL_HOST=lemmy-alpha:8541 - LEMMY_EXTERNAL_HOST=localhost:8541 @@ -58,7 +58,7 @@ services: - ./volumes/postgres_alpha:/var/lib/postgresql/data lemmy-beta-ui: - image: dessalines/lemmy-ui:0.10.2 + image: dessalines/lemmy-ui:0.10.3 environment: - LEMMY_INTERNAL_HOST=lemmy-beta:8551 - LEMMY_EXTERNAL_HOST=localhost:8551 @@ -87,7 +87,7 @@ services: - ./volumes/postgres_beta:/var/lib/postgresql/data lemmy-gamma-ui: - image: dessalines/lemmy-ui:0.10.2 + image: dessalines/lemmy-ui:0.10.3 environment: - LEMMY_INTERNAL_HOST=lemmy-gamma:8561 - LEMMY_EXTERNAL_HOST=localhost:8561