This commit is contained in:
2026-07-10 16:03:36 +02:00
parent 44d7df33a2
commit 2484f1e603
26 changed files with 217 additions and 224 deletions

View File

@@ -4,8 +4,8 @@ use chrono::NaiveDateTime;
use crate::{
errors::DomainError,
models::{
DiaryEntry, FederationFlags, RemoteActorInfo, RemoteGoalEntry,
RemoteWatchlistEntry, WatchlistWithMovie,
DiaryEntry, FederationFlags, RemoteActorInfo, RemoteGoalEntry, RemoteWatchlistEntry,
WatchlistWithMovie,
},
value_objects::{MovieId, SocialActor, SocialIdentity, UserId},
};
@@ -14,17 +14,10 @@ use crate::{
#[async_trait]
pub trait SocialCommand: Send + Sync {
async fn follow(
&self,
follower: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError>;
async fn follow(&self, follower: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
async fn unfollow(
&self,
follower: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError>;
async fn unfollow(&self, follower: &UserId, target: &SocialIdentity)
-> Result<(), DomainError>;
async fn accept_follow(
&self,
@@ -44,44 +37,24 @@ pub trait SocialCommand: Send + Sync {
follower: &SocialIdentity,
) -> Result<(), DomainError>;
async fn block(
&self,
blocker: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError>;
async fn block(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
async fn unblock(
&self,
blocker: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError>;
async fn unblock(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
}
#[async_trait]
pub trait SocialQuery: Send + Sync {
async fn get_following(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError>;
async fn get_following(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
async fn get_followers(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError>;
async fn get_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
async fn get_pending_followers(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError>;
async fn get_pending_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
async fn count_following(&self, user: &UserId) -> Result<usize, DomainError>;
async fn count_followers(&self, user: &UserId) -> Result<usize, DomainError>;
async fn get_blocked(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError>;
async fn get_blocked(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
async fn is_following(
&self,
@@ -93,7 +66,6 @@ pub trait SocialQuery: Send + Sync {
&self,
user_id: &UserId,
) -> Result<Vec<String>, DomainError>;
}
#[async_trait]

View File

@@ -893,11 +893,7 @@ impl InMemorySocialRepository {
#[async_trait]
impl SocialCommand for InMemorySocialRepository {
async fn follow(
&self,
follower: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError> {
async fn follow(&self, follower: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
if let SocialIdentity::Local(target_id) = target {
if follower == target_id {
return Err(DomainError::ValidationError(
@@ -925,7 +921,9 @@ impl SocialCommand for InMemorySocialRepository {
let before = store.len();
store.retain(|(f, t, _)| !(*f == follower.value() && t == target));
if store.len() == before {
return Err(DomainError::NotFound("Follow relationship not found".into()));
return Err(DomainError::NotFound(
"Follow relationship not found".into(),
));
}
Ok(())
}
@@ -1008,11 +1006,7 @@ impl SocialCommand for InMemorySocialRepository {
Ok(())
}
async fn block(
&self,
blocker: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError> {
async fn block(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
let mut store = self.blocked.lock().unwrap();
store.push((blocker.value(), target.clone()));
// Also remove any existing follow relationships
@@ -1021,11 +1015,7 @@ impl SocialCommand for InMemorySocialRepository {
Ok(())
}
async fn unblock(
&self,
blocker: &UserId,
target: &SocialIdentity,
) -> Result<(), DomainError> {
async fn unblock(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
let mut store = self.blocked.lock().unwrap();
store.retain(|(b, t)| !(*b == blocker.value() && t == target));
Ok(())
@@ -1034,10 +1024,7 @@ impl SocialCommand for InMemorySocialRepository {
#[async_trait]
impl SocialQuery for InMemorySocialRepository {
async fn get_following(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError> {
async fn get_following(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
let store = self.follows.lock().unwrap();
Ok(store
.iter()
@@ -1046,10 +1033,7 @@ impl SocialQuery for InMemorySocialRepository {
.collect())
}
async fn get_followers(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError> {
async fn get_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
let store = self.follows.lock().unwrap();
let target = SocialIdentity::Local(user.clone());
Ok(store
@@ -1062,10 +1046,7 @@ impl SocialQuery for InMemorySocialRepository {
.collect())
}
async fn get_pending_followers(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError> {
async fn get_pending_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
let store = self.follows.lock().unwrap();
let target = SocialIdentity::Local(user.clone());
Ok(store
@@ -1095,10 +1076,7 @@ impl SocialQuery for InMemorySocialRepository {
.count())
}
async fn get_blocked(
&self,
user: &UserId,
) -> Result<Vec<SocialActor>, DomainError> {
async fn get_blocked(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
let store = self.blocked.lock().unwrap();
Ok(store
.iter()
@@ -1113,9 +1091,9 @@ impl SocialQuery for InMemorySocialRepository {
target: &SocialIdentity,
) -> Result<bool, DomainError> {
let store = self.follows.lock().unwrap();
Ok(store
.iter()
.any(|(f, t, state)| *f == follower.value() && t == target && *state == FollowState::Accepted))
Ok(store.iter().any(|(f, t, state)| {
*f == follower.value() && t == target && *state == FollowState::Accepted
}))
}
async fn get_accepted_following_urls(

View File

@@ -64,8 +64,8 @@ impl ObjectStorage for NoopObjectStorage {
// Re-export production noop types so test code that imports from
// `domain::testing` keeps compiling without changes.
pub use crate::ports::noop::NoopRemoteWatchlistRepository;
pub use crate::ports::noop::NoopFederationAdminQuery;
pub use crate::ports::noop::NoopRemoteWatchlistRepository;
// ── NoopGoalCommand ───────────────────────────────────────────────────────────

View File

@@ -6,8 +6,8 @@ use crate::{
AnnotatedRow, DiaryEntry, DiaryFilter, EntityType, ExportFormat, ExternalPersonId,
FeedEntry, FeedSortBy, FieldMapping, FileFormat, FollowingFilter, ImportError,
ImportProfile, ImportSession, IndexableDocument, MovieProfile, MovieStats, ParsedFile,
Person, PersonCredits, PersonEnrichmentData, PersonId, RefreshSession,
RemoteActorInfo, ReviewHistory, SearchQuery, SearchResults, UserStats, UserTrends,
Person, PersonCredits, PersonEnrichmentData, PersonId, RefreshSession, RemoteActorInfo,
ReviewHistory, SearchQuery, SearchResults, UserStats, UserTrends,
collections::{PageParams, Paginated},
},
ports::{