feat(domain): RemoteActor fields, RemoteNote, FetchRemoteActorPosts event, fetch_outbox_page port
This commit is contained in:
@@ -1394,6 +1394,11 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
||||
public_key: actor.public_key_pem.clone(),
|
||||
avatar_url: actor.avatar_url.as_ref().map(|u| u.to_string()),
|
||||
last_fetched_at: actor.last_refreshed_at,
|
||||
bio: None,
|
||||
banner_url: None,
|
||||
also_known_as: None,
|
||||
outbox_url: None,
|
||||
attachment: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1511,6 +1516,16 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
||||
serde_json::to_string(&obj)
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))
|
||||
}
|
||||
|
||||
async fn fetch_outbox_page(
|
||||
&self,
|
||||
_outbox_url: &str,
|
||||
_page: u32,
|
||||
) -> Result<Vec<domain::models::remote_note::RemoteNote>, domain::errors::DomainError> {
|
||||
Err(domain::errors::DomainError::Internal(
|
||||
"not implemented".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -68,6 +68,10 @@ pub enum EventPayload {
|
||||
UserRegistered {
|
||||
user_id: String,
|
||||
},
|
||||
FetchRemoteActorPosts {
|
||||
actor_ap_url: String,
|
||||
outbox_url: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl EventPayload {
|
||||
@@ -88,6 +92,7 @@ impl EventPayload {
|
||||
Self::UserBlocked { .. } => "users.blocked",
|
||||
Self::UserUnblocked { .. } => "users.unblocked",
|
||||
Self::UserRegistered { .. } => "users.registered",
|
||||
Self::FetchRemoteActorPosts { .. } => "federation.fetch_outbox",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,6 +202,13 @@ impl From<&DomainEvent> for EventPayload {
|
||||
DomainEvent::UserRegistered { user_id } => Self::UserRegistered {
|
||||
user_id: user_id.to_string(),
|
||||
},
|
||||
DomainEvent::FetchRemoteActorPosts {
|
||||
actor_ap_url,
|
||||
outbox_url,
|
||||
} => Self::FetchRemoteActorPosts {
|
||||
actor_ap_url: actor_ap_url.clone(),
|
||||
outbox_url: outbox_url.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,6 +327,13 @@ impl TryFrom<EventPayload> for DomainEvent {
|
||||
EventPayload::UserRegistered { user_id } => DomainEvent::UserRegistered {
|
||||
user_id: UserId::from_uuid(parse_uuid(&user_id, "user_id")?),
|
||||
},
|
||||
EventPayload::FetchRemoteActorPosts {
|
||||
actor_ap_url,
|
||||
outbox_url,
|
||||
} => DomainEvent::FetchRemoteActorPosts {
|
||||
actor_ap_url,
|
||||
outbox_url,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,6 @@ impl RemoteActorRepository for PgRemoteActorRepository {
|
||||
"SELECT url,handle,display_name,inbox_url,shared_inbox_url,public_key,avatar_url,last_fetched_at FROM remote_actors WHERE url=$1"
|
||||
).bind(url).fetch_optional(&self.pool).await
|
||||
.map_err(|e| DomainError::Internal(e.to_string()))
|
||||
.map(|o| o.map(|r| RemoteActor { url: r.url, handle: r.handle, display_name: r.display_name, inbox_url: r.inbox_url, shared_inbox_url: r.shared_inbox_url, public_key: r.public_key, avatar_url: r.avatar_url, last_fetched_at: r.last_fetched_at }))
|
||||
.map(|o| o.map(|r| RemoteActor { url: r.url, handle: r.handle, display_name: r.display_name, inbox_url: r.inbox_url, shared_inbox_url: r.shared_inbox_url, public_key: r.public_key, avatar_url: r.avatar_url, last_fetched_at: r.last_fetched_at, bio: None, banner_url: None, also_known_as: None, outbox_url: None, attachment: vec![] }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ pub enum DomainEvent {
|
||||
UserRegistered {
|
||||
user_id: UserId,
|
||||
},
|
||||
FetchRemoteActorPosts {
|
||||
actor_ap_url: String,
|
||||
outbox_url: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct EventEnvelope {
|
||||
|
||||
@@ -2,6 +2,7 @@ pub mod api_key;
|
||||
pub mod feed;
|
||||
pub mod notification;
|
||||
pub mod remote_actor;
|
||||
pub mod remote_note;
|
||||
pub mod social;
|
||||
pub mod tag;
|
||||
pub mod thought;
|
||||
|
||||
@@ -10,4 +10,9 @@ pub struct RemoteActor {
|
||||
pub public_key: String,
|
||||
pub avatar_url: Option<String>,
|
||||
pub last_fetched_at: DateTime<Utc>,
|
||||
pub bio: Option<String>,
|
||||
pub banner_url: Option<String>,
|
||||
pub also_known_as: Option<String>,
|
||||
pub outbox_url: Option<String>,
|
||||
pub attachment: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
10
crates/domain/src/models/remote_note.rs
Normal file
10
crates/domain/src/models/remote_note.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteNote {
|
||||
pub ap_id: String,
|
||||
pub content: String,
|
||||
pub published: DateTime<Utc>,
|
||||
pub sensitive: bool,
|
||||
pub content_warning: Option<String>,
|
||||
}
|
||||
@@ -209,6 +209,11 @@ pub trait FederationActionPort: Send + Sync {
|
||||
user_id: &UserId,
|
||||
page: Option<u32>,
|
||||
) -> Result<String, DomainError>;
|
||||
async fn fetch_outbox_page(
|
||||
&self,
|
||||
outbox_url: &str,
|
||||
page: u32,
|
||||
) -> Result<Vec<crate::models::remote_note::RemoteNote>, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -567,6 +567,14 @@ impl FederationActionPort for TestStore {
|
||||
) -> Result<String, DomainError> {
|
||||
Err(DomainError::NotFound)
|
||||
}
|
||||
|
||||
async fn fetch_outbox_page(
|
||||
&self,
|
||||
_outbox_url: &str,
|
||||
_page: u32,
|
||||
) -> Result<Vec<crate::models::remote_note::RemoteNote>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -833,6 +841,16 @@ mod federation_port_tests {
|
||||
let err = store.actor_json(&UserId::new()).await.unwrap_err();
|
||||
assert!(matches!(err, DomainError::NotFound));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_store_fetch_outbox_returns_empty() {
|
||||
let store = TestStore::default();
|
||||
let notes = store
|
||||
.fetch_outbox_page("https://example.com/outbox", 1)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(notes.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user