feat(domain): FederationActionPort trait + avatar_url on RemoteActor
This commit is contained in:
@@ -44,6 +44,6 @@ impl RemoteActorRepository for PgRemoteActorRepository {
|
||||
"SELECT url,handle,display_name,inbox_url,shared_inbox_url,public_key,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, 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: None, last_fetched_at: r.last_fetched_at }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ pub enum DomainError {
|
||||
Conflict(String),
|
||||
#[error("invalid input: {0}")]
|
||||
InvalidInput(String),
|
||||
#[error("external service error: {0}")]
|
||||
ExternalService(String),
|
||||
#[error("internal error: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ pub struct RemoteActor {
|
||||
pub inbox_url: String,
|
||||
pub shared_inbox_url: Option<String>,
|
||||
pub public_key: String,
|
||||
pub avatar_url: Option<String>,
|
||||
pub last_fetched_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
@@ -194,6 +194,12 @@ pub trait RemoteActorRepository: Send + Sync {
|
||||
async fn find_by_url(&self, url: &str) -> Result<Option<RemoteActor>, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait FederationActionPort: Send + Sync {
|
||||
async fn lookup_actor(&self, handle: &str) -> Result<RemoteActor, DomainError>;
|
||||
async fn follow_remote(&self, local_user_id: &UserId, handle: &str) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait FeedRepository: Send + Sync {
|
||||
async fn home_feed(
|
||||
|
||||
@@ -534,6 +534,21 @@ impl RemoteActorRepository for TestStore {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FederationActionPort for TestStore {
|
||||
async fn lookup_actor(&self, _handle: &str) -> Result<RemoteActor, DomainError> {
|
||||
Err(DomainError::NotFound)
|
||||
}
|
||||
|
||||
async fn follow_remote(
|
||||
&self,
|
||||
_local_user_id: &UserId,
|
||||
_handle: &str,
|
||||
) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FeedRepository for TestStore {
|
||||
async fn home_feed(
|
||||
@@ -767,6 +782,32 @@ mod ap_repo_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod federation_port_tests {
|
||||
use super::*;
|
||||
use crate::value_objects::UserId;
|
||||
|
||||
fn uid() -> UserId {
|
||||
UserId::new()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_store_lookup_returns_not_found() {
|
||||
let store = TestStore::default();
|
||||
let err = store.lookup_actor("@alice@example.com").await.unwrap_err();
|
||||
assert!(matches!(err, DomainError::NotFound));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_store_follow_remote_is_noop_ok() {
|
||||
let store = TestStore::default();
|
||||
store
|
||||
.follow_remote(&uid(), "@alice@example.com")
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod search_tests {
|
||||
use super::*;
|
||||
|
||||
@@ -28,6 +28,9 @@ impl IntoResponse for ApiError {
|
||||
Self::Domain(DomainError::Forbidden) => (StatusCode::FORBIDDEN, "forbidden".into()),
|
||||
Self::Domain(DomainError::Conflict(m)) => (StatusCode::CONFLICT, m),
|
||||
Self::Domain(DomainError::InvalidInput(m)) => (StatusCode::UNPROCESSABLE_ENTITY, m),
|
||||
Self::Domain(DomainError::ExternalService(_)) => {
|
||||
(StatusCode::BAD_GATEWAY, "external service error".into())
|
||||
}
|
||||
Self::Domain(DomainError::Internal(_)) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"internal server error".into(),
|
||||
|
||||
Reference in New Issue
Block a user