ADR-0003: local follows bypass AP, unified FollowCommand/FollowQuery ports, FederationRepos struct, base_url normalization
Some checks failed
CI / Check / Test (push) Has been cancelled
Some checks failed
CI / Check / Test (push) Has been cancelled
This commit is contained in:
80
crates/domain/src/ports/follow.rs
Normal file
80
crates/domain/src/ports/follow.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
errors::DomainError,
|
||||
value_objects::{FollowStatus, SocialActor},
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait FollowCommand: Send + Sync {
|
||||
async fn add_follow(
|
||||
&self,
|
||||
follower_id: uuid::Uuid,
|
||||
target_actor_url: &str,
|
||||
status: FollowStatus,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn update_follow_status(
|
||||
&self,
|
||||
follower_id: uuid::Uuid,
|
||||
target_actor_url: &str,
|
||||
status: FollowStatus,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn remove_follow(
|
||||
&self,
|
||||
follower_id: uuid::Uuid,
|
||||
target_actor_url: &str,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn add_follower(
|
||||
&self,
|
||||
local_user_id: uuid::Uuid,
|
||||
follower_actor_url: &str,
|
||||
status: FollowStatus,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn update_follower_status(
|
||||
&self,
|
||||
local_user_id: uuid::Uuid,
|
||||
follower_actor_url: &str,
|
||||
status: FollowStatus,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn remove_follower_record(
|
||||
&self,
|
||||
local_user_id: uuid::Uuid,
|
||||
follower_actor_url: &str,
|
||||
) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait FollowQuery: Send + Sync {
|
||||
async fn get_following(
|
||||
&self,
|
||||
user_id: uuid::Uuid,
|
||||
base_url: &str,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn get_followers(
|
||||
&self,
|
||||
user_id: uuid::Uuid,
|
||||
base_url: &str,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user_id: uuid::Uuid,
|
||||
base_url: &str,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn count_following(&self, user_id: uuid::Uuid) -> Result<usize, DomainError>;
|
||||
|
||||
async fn count_followers(&self, user_id: uuid::Uuid) -> Result<usize, DomainError>;
|
||||
|
||||
async fn is_following(
|
||||
&self,
|
||||
follower_id: uuid::Uuid,
|
||||
target_actor_url: &str,
|
||||
) -> Result<bool, DomainError>;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pub mod auth;
|
||||
pub mod diary;
|
||||
pub mod events;
|
||||
pub mod federated_profile;
|
||||
pub mod follow;
|
||||
pub mod goals;
|
||||
pub mod image_fetcher;
|
||||
pub mod images;
|
||||
@@ -21,6 +22,7 @@ pub use auth::*;
|
||||
pub use diary::*;
|
||||
pub use events::*;
|
||||
pub use federated_profile::*;
|
||||
pub use follow::*;
|
||||
pub use goals::*;
|
||||
pub use image_fetcher::*;
|
||||
pub use images::*;
|
||||
|
||||
@@ -7,6 +7,18 @@ pub enum SocialIdentity {
|
||||
}
|
||||
|
||||
impl SocialIdentity {
|
||||
pub fn from_actor_url(actor_url: &str, base_url: &str) -> Self {
|
||||
let prefix = format!("{}/users/", base_url);
|
||||
if let Some(uuid_str) = actor_url.strip_prefix(&prefix)
|
||||
&& let Ok(uuid) = uuid::Uuid::parse_str(uuid_str)
|
||||
{
|
||||
return Self::Local(UserId::from_uuid(uuid));
|
||||
}
|
||||
Self::Remote {
|
||||
actor_url: actor_url.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_local(&self) -> bool {
|
||||
matches!(self, Self::Local(_))
|
||||
}
|
||||
@@ -14,6 +26,26 @@ impl SocialIdentity {
|
||||
pub fn is_remote(&self) -> bool {
|
||||
matches!(self, Self::Remote { .. })
|
||||
}
|
||||
|
||||
pub fn format_local_handle(username: &str, base_url: &str) -> String {
|
||||
let host = Self::host_from_base_url(base_url);
|
||||
format!("@{}@{}", username, host)
|
||||
}
|
||||
|
||||
pub fn host_from_base_url(base_url: &str) -> &str {
|
||||
base_url
|
||||
.split("://")
|
||||
.nth(1)
|
||||
.and_then(|s| s.split('/').next())
|
||||
.unwrap_or("localhost")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum FollowStatus {
|
||||
Pending,
|
||||
Accepted,
|
||||
Rejected,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
||||
Reference in New Issue
Block a user