From 2567103587b1534255c1e165ba4643ac8fe9e350 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 13 May 2026 01:28:03 +0200 Subject: [PATCH] feat: publish FollowAccepted event when remote accepts follow --- crates/adapters/activitypub-base/Cargo.toml | 2 ++ .../activitypub-base/src/activities.rs | 19 +++++++++++++++++++ crates/adapters/activitypub-base/src/data.rs | 4 ++++ .../adapters/activitypub-base/src/service.rs | 6 +++++- crates/adapters/activitypub/src/lib.rs | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/crates/adapters/activitypub-base/Cargo.toml b/crates/adapters/activitypub-base/Cargo.toml index bf104fa..25fa908 100644 --- a/crates/adapters/activitypub-base/Cargo.toml +++ b/crates/adapters/activitypub-base/Cargo.toml @@ -17,3 +17,5 @@ axum = { workspace = true } activitypub_federation = "0.7.0-beta.11" url = { version = "2", features = ["serde"] } enum_delegate = "0.2" +domain = { workspace = true } +reqwest = { workspace = true } diff --git a/crates/adapters/activitypub-base/src/activities.rs b/crates/adapters/activitypub-base/src/activities.rs index 2737709..56951ad 100644 --- a/crates/adapters/activitypub-base/src/activities.rs +++ b/crates/adapters/activitypub-base/src/activities.rs @@ -17,6 +17,7 @@ use crate::actors::DbActor; use crate::data::FederationData; use crate::error::Error; use crate::repository::{FollowerStatus, FollowingStatus}; +use domain::{events::DomainEvent, value_objects::UserId}; // --- Follow --- @@ -141,6 +142,24 @@ impl Activity for AcceptActivity { FollowingStatus::Accepted, ) .await?; + + if let Ok(Some(outbox_url)) = data + .federation_repo + .get_following_outbox_url(local_user_id, self.actor.inner().as_str()) + .await + { + let event = DomainEvent::FollowAccepted { + local_user_id: UserId::from_uuid(local_user_id), + remote_actor_url: self.actor.inner().to_string(), + outbox_url, + }; + if let Some(publisher) = &data.event_publisher { + if let Err(e) = publisher.publish(&event).await { + tracing::warn!(error = %e, "failed to publish FollowAccepted event"); + } + } + } + tracing::info!(remote_actor = %self.actor.inner(), "follow accepted by remote"); Ok(()) } diff --git a/crates/adapters/activitypub-base/src/data.rs b/crates/adapters/activitypub-base/src/data.rs index 885d08e..a4079f6 100644 --- a/crates/adapters/activitypub-base/src/data.rs +++ b/crates/adapters/activitypub-base/src/data.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use crate::content::ApObjectHandler; use crate::repository::FederationRepository; use crate::user::ApUserRepository; +use domain::ports::EventPublisher; #[derive(Clone)] pub struct FederationData { @@ -13,6 +14,7 @@ pub struct FederationData { pub(crate) domain: String, pub(crate) allow_registration: bool, pub(crate) software_name: String, + pub(crate) event_publisher: Option>, } impl FederationData { @@ -23,6 +25,7 @@ impl FederationData { base_url: String, allow_registration: bool, software_name: String, + event_publisher: Option>, ) -> Self { let domain = base_url .trim_start_matches("https://") @@ -39,6 +42,7 @@ impl FederationData { domain, allow_registration, software_name, + event_publisher, } } } diff --git a/crates/adapters/activitypub-base/src/service.rs b/crates/adapters/activitypub-base/src/service.rs index 3ebd41c..992ff62 100644 --- a/crates/adapters/activitypub-base/src/service.rs +++ b/crates/adapters/activitypub-base/src/service.rs @@ -81,8 +81,12 @@ impl ActivityPubService { allow_registration: bool, software_name: String, debug: bool, + event_publisher: Option>, ) -> anyhow::Result { - let data = FederationData::new(repo, user_repo, object_handler, base_url.clone(), allow_registration, software_name); + let data = FederationData::new( + repo, user_repo, object_handler, base_url.clone(), + allow_registration, software_name, event_publisher, + ); let federation_config = ApFederationConfig::new(data, debug).await?; Ok(Self { federation_config, diff --git a/crates/adapters/activitypub/src/lib.rs b/crates/adapters/activitypub/src/lib.rs index 4f36489..0ea746c 100644 --- a/crates/adapters/activitypub/src/lib.rs +++ b/crates/adapters/activitypub/src/lib.rs @@ -60,6 +60,7 @@ pub async fn wire( allow_registration, "movies-diary".to_string(), cfg!(debug_assertions), + None, // event_publisher wired in Task 6 ) .await?, );