refactor: LOW+MEDIUM cleanups — CQRS DiaryQuery/GoalCommand+GoalQuery,
test-helpers out of production, decompose get_user_profile_html, dedup secure_flag, remove vestigial social_query, drop PersistedImportSession, LoginCommand rename, DeleteAccountDeps, PersonId macro, ReviewSortBy rename, TUI Command for fs::read, generic PaginatedResponse<T>, noop ports for production fallbacks
This commit is contained in:
@@ -11,7 +11,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait DiaryRepository: Send + Sync {
|
||||
pub trait DiaryQuery: Send + Sync {
|
||||
async fn query_diary(&self, filter: &DiaryFilter)
|
||||
-> Result<Paginated<DiaryEntry>, DomainError>;
|
||||
async fn query_activity_feed(
|
||||
|
||||
@@ -7,10 +7,14 @@ use crate::{
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait GoalRepository: Send + Sync {
|
||||
pub trait GoalCommand: Send + Sync {
|
||||
async fn save(&self, goal: &Goal) -> Result<(), DomainError>;
|
||||
async fn update(&self, goal: &Goal) -> Result<(), DomainError>;
|
||||
async fn delete(&self, id: &GoalId, user_id: &UserId) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GoalQuery: Send + Sync {
|
||||
async fn find_by_user_and_year(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod import;
|
||||
pub mod jobs;
|
||||
pub mod media_server;
|
||||
pub mod movie;
|
||||
pub mod noop;
|
||||
pub mod person;
|
||||
pub mod rss;
|
||||
pub mod search;
|
||||
|
||||
65
crates/domain/src/ports/noop.rs
Normal file
65
crates/domain/src/ports/noop.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{errors::DomainError, value_objects::UserId};
|
||||
|
||||
// ── NoopRemoteWatchlistRepository ─────────────────────────────────────────────
|
||||
|
||||
/// Stub used when federation is disabled — every operation is a no-op.
|
||||
pub struct NoopRemoteWatchlistRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl super::RemoteWatchlistRepository for NoopRemoteWatchlistRepository {
|
||||
async fn save(&self, _: crate::models::RemoteWatchlistEntry) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn remove_by_ap_id(&self, _: &str, _: &str) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn get_by_actor_url(
|
||||
&self,
|
||||
_: &str,
|
||||
) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn remove_all_by_actor(&self, _: &str) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn get_by_derived_uuid(
|
||||
&self,
|
||||
_: uuid::Uuid,
|
||||
) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
// ── NoopSocialQueryPort ───────────────────────────────────────────────────────
|
||||
|
||||
/// Stub used when federation is disabled — returns empty results.
|
||||
pub struct NoopSocialQueryPort;
|
||||
|
||||
#[async_trait]
|
||||
impl super::SocialQueryPort for NoopSocialQueryPort {
|
||||
async fn get_accepted_following_urls(
|
||||
&self,
|
||||
_: &UserId,
|
||||
) -> Result<Vec<String>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn list_all_followed_remote_actors(
|
||||
&self,
|
||||
) -> Result<Vec<crate::models::RemoteActorInfo>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn count_following(&self, _: &UserId) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
async fn count_accepted_followers(&self, _: &UserId) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
_: &UserId,
|
||||
) -> Result<Vec<crate::models::PendingFollowerInfo>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ use crate::{
|
||||
collections::{PageParams, Paginated},
|
||||
},
|
||||
ports::{
|
||||
AuthService, DiaryRepository, DocumentParser, MetadataClient, MovieEnrichmentClient,
|
||||
AuthService, DiaryQuery, DocumentParser, MetadataClient, MovieEnrichmentClient,
|
||||
PasswordHasher, PersonQuery, PosterFetcherClient, SearchCommand, SearchPort,
|
||||
StatsRepository,
|
||||
},
|
||||
@@ -81,13 +81,13 @@ impl MetadataClient for FakeMetadataClient {
|
||||
}
|
||||
}
|
||||
|
||||
// ── FakeDiaryRepository ───────────────────────────────────────────────────────
|
||||
// ── FakeDiaryQuery ────────────────────────────────────────────────────────────
|
||||
|
||||
pub struct FakeDiaryRepository {
|
||||
pub struct FakeDiaryQuery {
|
||||
histories: Mutex<HashMap<Uuid, (Movie, Vec<Review>)>>,
|
||||
}
|
||||
|
||||
impl FakeDiaryRepository {
|
||||
impl FakeDiaryQuery {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
histories: Mutex::new(HashMap::new()),
|
||||
@@ -103,7 +103,7 @@ impl FakeDiaryRepository {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl DiaryRepository for FakeDiaryRepository {
|
||||
impl DiaryQuery for FakeDiaryQuery {
|
||||
async fn query_diary(
|
||||
&self,
|
||||
_filter: &DiaryFilter,
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
collections::{PageParams, Paginated},
|
||||
},
|
||||
ports::{
|
||||
GoalRepository, ImportProfileRepository, ImportSessionRepository, MovieCommand,
|
||||
GoalCommand, GoalQuery, ImportProfileRepository, ImportSessionRepository, MovieCommand,
|
||||
MovieProfileRepository, MovieQuery, RefreshSessionRepository, ReviewRepository,
|
||||
UserFederationSettingsQuery, UserProfileFieldsRepository, UserRepository,
|
||||
UserSettingsRepository, WatchEventCommand, WatchEventQuery, WatchlistRepository,
|
||||
@@ -357,7 +357,7 @@ impl InMemoryGoalRepository {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GoalRepository for InMemoryGoalRepository {
|
||||
impl GoalCommand for InMemoryGoalRepository {
|
||||
async fn save(&self, goal: &Goal) -> Result<(), DomainError> {
|
||||
self.store
|
||||
.lock()
|
||||
@@ -383,7 +383,10 @@ impl GoalRepository for InMemoryGoalRepository {
|
||||
self.store.lock().unwrap().remove(&id.value());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GoalQuery for InMemoryGoalRepository {
|
||||
async fn find_by_user_and_year(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
|
||||
@@ -62,78 +62,17 @@ impl ObjectStorage for NoopObjectStorage {
|
||||
}
|
||||
}
|
||||
|
||||
// ── NoopRemoteWatchlistRepository ─────────────────────────────────────────────
|
||||
// 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::NoopSocialQueryPort;
|
||||
|
||||
pub struct NoopRemoteWatchlistRepository;
|
||||
// ── NoopGoalCommand ───────────────────────────────────────────────────────────
|
||||
|
||||
pub struct NoopGoalCommand;
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ports::RemoteWatchlistRepository for NoopRemoteWatchlistRepository {
|
||||
async fn save(&self, _: crate::models::RemoteWatchlistEntry) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn remove_by_ap_id(&self, _: &str, _: &str) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn get_by_actor_url(
|
||||
&self,
|
||||
_: &str,
|
||||
) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn remove_all_by_actor(&self, _: &str) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
async fn get_by_derived_uuid(
|
||||
&self,
|
||||
_: uuid::Uuid,
|
||||
) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
// ── NoopSocialQueryPort ───────────────────────────────────────────────────────
|
||||
|
||||
pub struct NoopSocialQueryPort;
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ports::SocialQueryPort for NoopSocialQueryPort {
|
||||
async fn get_accepted_following_urls(
|
||||
&self,
|
||||
_: &crate::value_objects::UserId,
|
||||
) -> Result<Vec<String>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn list_all_followed_remote_actors(
|
||||
&self,
|
||||
) -> Result<Vec<crate::models::RemoteActorInfo>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn count_following(
|
||||
&self,
|
||||
_: &crate::value_objects::UserId,
|
||||
) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
async fn count_accepted_followers(
|
||||
&self,
|
||||
_: &crate::value_objects::UserId,
|
||||
) -> Result<usize, DomainError> {
|
||||
Ok(0)
|
||||
}
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
_: &crate::value_objects::UserId,
|
||||
) -> Result<Vec<crate::models::PendingFollowerInfo>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
// ── NoopGoalRepository ────────────────────────────────────────────────────────
|
||||
|
||||
pub struct NoopGoalRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ports::GoalRepository for NoopGoalRepository {
|
||||
impl crate::ports::GoalCommand for NoopGoalCommand {
|
||||
async fn save(&self, _: &crate::models::Goal) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -147,6 +86,14 @@ impl crate::ports::GoalRepository for NoopGoalRepository {
|
||||
) -> Result<(), DomainError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ── NoopGoalQuery ─────────────────────────────────────────────────────────────
|
||||
|
||||
pub struct NoopGoalQuery;
|
||||
|
||||
#[async_trait]
|
||||
impl crate::ports::GoalQuery for NoopGoalQuery {
|
||||
async fn find_by_user_and_year(
|
||||
&self,
|
||||
_: &UserId,
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
collections::{PageParams, Paginated},
|
||||
},
|
||||
ports::{
|
||||
DiaryExporter, DiaryRepository, DocumentParser, ImportProfileRepository,
|
||||
DiaryExporter, DiaryQuery, DocumentParser, ImportProfileRepository,
|
||||
ImportSessionRepository, MovieProfileRepository, PersonCommand, PersonQuery,
|
||||
PosterFetcherClient, RefreshSessionRepository, SearchCommand, SearchPort, StatsRepository,
|
||||
UserProfileFieldsRepository,
|
||||
@@ -19,20 +19,20 @@ use crate::{
|
||||
value_objects::{ImportProfileId, ImportSessionId, MovieId, PosterUrl, UserId},
|
||||
};
|
||||
|
||||
// ── PanicDiaryRepository ──────────────────────────────────────────────────────
|
||||
// ── PanicDiaryQuery ───────────────────────────────────────────────────────────
|
||||
|
||||
pub struct PanicDiaryRepository;
|
||||
pub struct PanicDiaryQuery;
|
||||
|
||||
#[async_trait]
|
||||
impl DiaryRepository for PanicDiaryRepository {
|
||||
impl DiaryQuery for PanicDiaryQuery {
|
||||
async fn query_diary(&self, _: &DiaryFilter) -> Result<Paginated<DiaryEntry>, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn query_activity_feed(
|
||||
&self,
|
||||
_: &PageParams,
|
||||
) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn query_activity_feed_filtered(
|
||||
&self,
|
||||
@@ -41,32 +41,32 @@ impl DiaryRepository for PanicDiaryRepository {
|
||||
_: Option<&str>,
|
||||
_: Option<&FollowingFilter>,
|
||||
) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn get_review_history(&self, _: &MovieId) -> Result<ReviewHistory, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn get_user_history(&self, _: &UserId) -> Result<Vec<DiaryEntry>, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
fn stream_user_history(
|
||||
&self,
|
||||
_: UserId,
|
||||
) -> futures::stream::BoxStream<'static, Result<DiaryEntry, DomainError>> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn get_movie_stats(&self, _: &MovieId) -> Result<MovieStats, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn get_movie_social_feed(
|
||||
&self,
|
||||
_: &MovieId,
|
||||
_: &PageParams,
|
||||
) -> Result<Paginated<FeedEntry>, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
async fn count_local_posts(&self) -> Result<u64, DomainError> {
|
||||
panic!("PanicDiaryRepository called")
|
||||
panic!("PanicDiaryQuery called")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user