From faeac181265686e389890d140ca1bea4e66385e8 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 13 May 2026 01:20:48 +0200 Subject: [PATCH] feat: add outbox_url to RemoteActor, get_following_outbox_url to FederationRepository --- crates/adapters/activitypub-base/src/actors.rs | 1 + crates/adapters/activitypub-base/src/repository.rs | 6 ++++++ crates/adapters/activitypub-base/src/service.rs | 3 +++ .../adapters/activitypub-base/src/tests/service.rs | 1 + crates/adapters/event-payload/src/lib.rs | 6 ++++-- crates/adapters/postgres-federation/src/lib.rs | 13 ++++++++++++- crates/adapters/sqlite-federation/src/lib.rs | 12 ++++++++++++ 7 files changed, 39 insertions(+), 3 deletions(-) diff --git a/crates/adapters/activitypub-base/src/actors.rs b/crates/adapters/activitypub-base/src/actors.rs index da53591..b003206 100644 --- a/crates/adapters/activitypub-base/src/actors.rs +++ b/crates/adapters/activitypub-base/src/actors.rs @@ -219,6 +219,7 @@ impl Object for DbActor { shared_inbox_url: None, display_name: json.name.clone(), avatar_url: json.icon.as_ref().map(|i| i.url.to_string()), + outbox_url: Some(json.outbox.to_string()), }; data.federation_repo.upsert_remote_actor(actor).await?; diff --git a/crates/adapters/activitypub-base/src/repository.rs b/crates/adapters/activitypub-base/src/repository.rs index 12015a7..2a7b26a 100644 --- a/crates/adapters/activitypub-base/src/repository.rs +++ b/crates/adapters/activitypub-base/src/repository.rs @@ -22,6 +22,7 @@ pub struct RemoteActor { pub shared_inbox_url: Option, pub display_name: Option, pub avatar_url: Option, + pub outbox_url: Option, } #[derive(Debug, Clone)] @@ -96,6 +97,11 @@ pub trait FederationRepository: Send + Sync { remote_actor_url: &str, status: FollowingStatus, ) -> Result<()>; + async fn get_following_outbox_url( + &self, + local_user_id: uuid::Uuid, + remote_actor_url: &str, + ) -> Result>; async fn add_announce( &self, activity_id: &str, diff --git a/crates/adapters/activitypub-base/src/service.rs b/crates/adapters/activitypub-base/src/service.rs index 79e3303..3ebd41c 100644 --- a/crates/adapters/activitypub-base/src/service.rs +++ b/crates/adapters/activitypub-base/src/service.rs @@ -173,6 +173,7 @@ impl ActivityPubService { shared_inbox_url: None, display_name: Some(remote_actor.username.clone()), avatar_url: None, + outbox_url: Some(remote_actor.outbox_url.to_string()), }; data.federation_repo .add_following(local_user_id, remote, &follow_id_str) @@ -867,6 +868,7 @@ impl ActivityPubService { shared_inbox_url: None, display_name: None, avatar_url: None, + outbox_url: None, }, }; actors.push(actor); @@ -928,6 +930,7 @@ impl ActivityPubService { shared_inbox_url: None, display_name: Some(target.username), avatar_url: None, + outbox_url: None, }; data.federation_repo .add_following(local_user_id, target_as_remote, &follow_id) diff --git a/crates/adapters/activitypub-base/src/tests/service.rs b/crates/adapters/activitypub-base/src/tests/service.rs index 7c42c48..0ac7bcb 100644 --- a/crates/adapters/activitypub-base/src/tests/service.rs +++ b/crates/adapters/activitypub-base/src/tests/service.rs @@ -10,6 +10,7 @@ fn make_follower(inbox: &str, shared: Option<&str>) -> Follower { shared_inbox_url: shared.map(|s| s.to_string()), display_name: None, avatar_url: None, + outbox_url: None, }, status: FollowerStatus::Accepted, } diff --git a/crates/adapters/event-payload/src/lib.rs b/crates/adapters/event-payload/src/lib.rs index 480812a..44cf986 100644 --- a/crates/adapters/event-payload/src/lib.rs +++ b/crates/adapters/event-payload/src/lib.rs @@ -119,9 +119,11 @@ impl From<&DomainEvent> for EventPayload { } } DomainEvent::ImageStored { key } => EventPayload::ImageStored { key: key.clone() }, - DomainEvent::WatchlistEntryAdded { .. } | DomainEvent::WatchlistEntryRemoved { .. } => { + DomainEvent::WatchlistEntryAdded { .. } + | DomainEvent::WatchlistEntryRemoved { .. } + | DomainEvent::FollowAccepted { .. } => { // federation-only events; not serialized via EventPayload - unreachable!("watchlist events are handled by the AP event handler directly") + unreachable!("federation events are handled by the AP event handler directly") } } } diff --git a/crates/adapters/postgres-federation/src/lib.rs b/crates/adapters/postgres-federation/src/lib.rs index 90ac34d..d47736b 100644 --- a/crates/adapters/postgres-federation/src/lib.rs +++ b/crates/adapters/postgres-federation/src/lib.rs @@ -121,7 +121,7 @@ impl FederationRepository for PostgresFederationRepository { let display_name: Option = row.try_get("display_name").ok().flatten(); let avatar_url: Option = row.try_get("avatar_url").ok().flatten(); Follower { - actor: RemoteActor { url, handle, inbox_url, shared_inbox_url, display_name, avatar_url }, + actor: RemoteActor { url, handle, inbox_url, shared_inbox_url, display_name, avatar_url, outbox_url: row.try_get("outbox_url").ok().flatten() }, status: str_to_status(&status_str), } }).collect()) @@ -217,6 +217,7 @@ impl FederationRepository for PostgresFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), }).collect()) } @@ -272,6 +273,7 @@ impl FederationRepository for PostgresFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), })) } @@ -327,6 +329,7 @@ impl FederationRepository for PostgresFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), }).collect()) } @@ -355,6 +358,14 @@ impl FederationRepository for PostgresFederationRepository { Ok(()) } + async fn get_following_outbox_url( + &self, + _local_user_id: uuid::Uuid, + _remote_actor_url: &str, + ) -> Result> { + Ok(None) + } + async fn add_announce( &self, activity_id: &str, diff --git a/crates/adapters/sqlite-federation/src/lib.rs b/crates/adapters/sqlite-federation/src/lib.rs index f35c5ad..de08c86 100644 --- a/crates/adapters/sqlite-federation/src/lib.rs +++ b/crates/adapters/sqlite-federation/src/lib.rs @@ -136,6 +136,7 @@ impl FederationRepository for SqliteFederationRepository { shared_inbox_url, display_name, avatar_url, + outbox_url: row.try_get("outbox_url").ok().flatten(), }, status: str_to_status(&status_str), } @@ -244,6 +245,7 @@ impl FederationRepository for SqliteFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), }) .collect()) } @@ -303,6 +305,7 @@ impl FederationRepository for SqliteFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), })) } @@ -369,6 +372,7 @@ impl FederationRepository for SqliteFederationRepository { shared_inbox_url: row.try_get("shared_inbox_url").ok().flatten(), display_name: row.try_get("display_name").ok().flatten(), avatar_url: row.try_get("avatar_url").ok().flatten(), + outbox_url: row.try_get("outbox_url").ok().flatten(), }) .collect()) } @@ -401,6 +405,14 @@ impl FederationRepository for SqliteFederationRepository { Ok(()) } + async fn get_following_outbox_url( + &self, + _local_user_id: uuid::Uuid, + _remote_actor_url: &str, + ) -> Result> { + Ok(None) + } + async fn add_announce( &self, activity_id: &str,