feat(domain): ActorConnectionSummary, ConnectionType, RemoteActorConnectionRepository, FetchActorConnections event

This commit is contained in:
2026-05-15 00:25:54 +02:00
parent 23501f5203
commit 99dd89b60d
8 changed files with 178 additions and 0 deletions

View File

@@ -64,6 +64,12 @@ pub enum DomainEvent {
actor_ap_url: String,
outbox_url: String,
},
FetchActorConnections {
actor_ap_url: String,
collection_url: String,
connection_type: String,
page: u32,
},
}
pub struct EventEnvelope {

View File

@@ -0,0 +1,7 @@
#[derive(Debug, Clone)]
pub struct ActorConnectionSummary {
pub url: String,
pub handle: String,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
}

View File

@@ -0,0 +1,14 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConnectionType {
Followers,
Following,
}
impl ConnectionType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Followers => "followers",
Self::Following => "following",
}
}
}

View File

@@ -1,4 +1,6 @@
pub mod actor_connection_summary;
pub mod api_key;
pub mod connection_type;
pub mod feed;
pub mod notification;
pub mod remote_actor;

View File

@@ -194,6 +194,31 @@ pub trait RemoteActorRepository: Send + Sync {
async fn find_by_url(&self, url: &str) -> Result<Option<RemoteActor>, DomainError>;
}
#[async_trait]
pub trait RemoteActorConnectionRepository: Send + Sync {
async fn upsert_connections(
&self,
actor_url: &str,
connection_type: &str,
page: u32,
actors: &[crate::models::actor_connection_summary::ActorConnectionSummary],
) -> Result<(), DomainError>;
async fn list_connections(
&self,
actor_url: &str,
connection_type: &str,
page: u32,
) -> Result<Vec<crate::models::actor_connection_summary::ActorConnectionSummary>, DomainError>;
async fn connection_page_age(
&self,
actor_url: &str,
connection_type: &str,
page: u32,
) -> Result<Option<chrono::DateTime<chrono::Utc>>, DomainError>;
}
#[async_trait]
pub trait FederationActionPort: Send + Sync {
async fn lookup_actor(&self, handle: &str) -> Result<RemoteActor, DomainError>;
@@ -214,6 +239,16 @@ pub trait FederationActionPort: Send + Sync {
outbox_url: &str,
page: u32,
) -> Result<Vec<crate::models::remote_note::RemoteNote>, DomainError>;
async fn fetch_actor_urls_from_collection(
&self,
collection_url: &str,
) -> Result<Vec<String>, DomainError>;
async fn resolve_actor_profiles(
&self,
urls: Vec<String>,
) -> Vec<crate::models::actor_connection_summary::ActorConnectionSummary>;
}
#[async_trait]

View File

@@ -575,6 +575,52 @@ impl FederationActionPort for TestStore {
) -> Result<Vec<crate::models::remote_note::RemoteNote>, DomainError> {
Ok(vec![])
}
async fn fetch_actor_urls_from_collection(
&self,
_collection_url: &str,
) -> Result<Vec<String>, DomainError> {
Ok(vec![])
}
async fn resolve_actor_profiles(
&self,
_urls: Vec<String>,
) -> Vec<crate::models::actor_connection_summary::ActorConnectionSummary> {
vec![]
}
}
#[async_trait]
impl RemoteActorConnectionRepository for TestStore {
async fn upsert_connections(
&self,
_actor_url: &str,
_connection_type: &str,
_page: u32,
_actors: &[crate::models::actor_connection_summary::ActorConnectionSummary],
) -> Result<(), DomainError> {
Ok(())
}
async fn list_connections(
&self,
_actor_url: &str,
_connection_type: &str,
_page: u32,
) -> Result<Vec<crate::models::actor_connection_summary::ActorConnectionSummary>, DomainError>
{
Ok(vec![])
}
async fn connection_page_age(
&self,
_actor_url: &str,
_connection_type: &str,
_page: u32,
) -> Result<Option<chrono::DateTime<chrono::Utc>>, DomainError> {
Ok(None)
}
}
#[async_trait]
@@ -851,6 +897,25 @@ mod federation_port_tests {
.unwrap();
assert!(notes.is_empty());
}
#[tokio::test]
async fn test_store_resolve_actor_profiles_returns_empty() {
let store = TestStore::default();
let result = store
.resolve_actor_profiles(vec!["https://example.com/users/alice".into()])
.await;
assert!(result.is_empty());
}
#[tokio::test]
async fn test_store_fetch_collection_urls_returns_empty() {
let store = TestStore::default();
let urls = store
.fetch_actor_urls_from_collection("https://example.com/users/alice/followers")
.await
.unwrap();
assert!(urls.is_empty());
}
}
#[cfg(test)]