feat: publish FollowAccepted event when remote accepts follow

This commit is contained in:
2026-05-13 01:28:03 +02:00
parent b1d4b4de2d
commit 2567103587
5 changed files with 31 additions and 1 deletions

View File

@@ -17,3 +17,5 @@ axum = { workspace = true }
activitypub_federation = "0.7.0-beta.11" activitypub_federation = "0.7.0-beta.11"
url = { version = "2", features = ["serde"] } url = { version = "2", features = ["serde"] }
enum_delegate = "0.2" enum_delegate = "0.2"
domain = { workspace = true }
reqwest = { workspace = true }

View File

@@ -17,6 +17,7 @@ use crate::actors::DbActor;
use crate::data::FederationData; use crate::data::FederationData;
use crate::error::Error; use crate::error::Error;
use crate::repository::{FollowerStatus, FollowingStatus}; use crate::repository::{FollowerStatus, FollowingStatus};
use domain::{events::DomainEvent, value_objects::UserId};
// --- Follow --- // --- Follow ---
@@ -141,6 +142,24 @@ impl Activity for AcceptActivity {
FollowingStatus::Accepted, FollowingStatus::Accepted,
) )
.await?; .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"); tracing::info!(remote_actor = %self.actor.inner(), "follow accepted by remote");
Ok(()) Ok(())
} }

View File

@@ -3,6 +3,7 @@ use std::sync::Arc;
use crate::content::ApObjectHandler; use crate::content::ApObjectHandler;
use crate::repository::FederationRepository; use crate::repository::FederationRepository;
use crate::user::ApUserRepository; use crate::user::ApUserRepository;
use domain::ports::EventPublisher;
#[derive(Clone)] #[derive(Clone)]
pub struct FederationData { pub struct FederationData {
@@ -13,6 +14,7 @@ pub struct FederationData {
pub(crate) domain: String, pub(crate) domain: String,
pub(crate) allow_registration: bool, pub(crate) allow_registration: bool,
pub(crate) software_name: String, pub(crate) software_name: String,
pub(crate) event_publisher: Option<Arc<dyn EventPublisher>>,
} }
impl FederationData { impl FederationData {
@@ -23,6 +25,7 @@ impl FederationData {
base_url: String, base_url: String,
allow_registration: bool, allow_registration: bool,
software_name: String, software_name: String,
event_publisher: Option<Arc<dyn EventPublisher>>,
) -> Self { ) -> Self {
let domain = base_url let domain = base_url
.trim_start_matches("https://") .trim_start_matches("https://")
@@ -39,6 +42,7 @@ impl FederationData {
domain, domain,
allow_registration, allow_registration,
software_name, software_name,
event_publisher,
} }
} }
} }

View File

@@ -81,8 +81,12 @@ impl ActivityPubService {
allow_registration: bool, allow_registration: bool,
software_name: String, software_name: String,
debug: bool, debug: bool,
event_publisher: Option<Arc<dyn domain::ports::EventPublisher>>,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
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?; let federation_config = ApFederationConfig::new(data, debug).await?;
Ok(Self { Ok(Self {
federation_config, federation_config,

View File

@@ -60,6 +60,7 @@ pub async fn wire(
allow_registration, allow_registration,
"movies-diary".to_string(), "movies-diary".to_string(),
cfg!(debug_assertions), cfg!(debug_assertions),
None, // event_publisher wired in Task 6
) )
.await?, .await?,
); );