diff --git a/crates/application/src/diary/delete_review.rs b/crates/application/src/diary/delete_review.rs index 9cdad14..8a260dd 100644 --- a/crates/application/src/diary/delete_review.rs +++ b/crates/application/src/diary/delete_review.rs @@ -1,16 +1,15 @@ -use crate::{context::AppContext, diary::commands::DeleteReviewCommand}; +use crate::diary::{commands::DeleteReviewCommand, deps::DeleteReviewDeps}; use domain::{ errors::DomainError, events::DomainEvent, value_objects::{ReviewId, UserId}, }; -pub async fn execute(ctx: &AppContext, cmd: DeleteReviewCommand) -> Result<(), DomainError> { +pub async fn execute(deps: &DeleteReviewDeps, cmd: DeleteReviewCommand) -> Result<(), DomainError> { let review_id = ReviewId::from_uuid(cmd.review_id); let requesting_user_id = UserId::from_uuid(cmd.requesting_user_id); - let review = ctx - .repos + let review = deps .review .get_review_by_id(&review_id) .await? @@ -21,10 +20,9 @@ pub async fn execute(ctx: &AppContext, cmd: DeleteReviewCommand) -> Result<(), D } let movie_id = review.movie_id().clone(); - ctx.repos.review.delete_review(&review_id).await?; + deps.review.delete_review(&review_id).await?; - if let Err(e) = ctx - .services + if let Err(e) = deps .event_publisher .publish(&DomainEvent::ReviewDeleted { review_id: review_id.clone(), @@ -35,13 +33,12 @@ pub async fn execute(ctx: &AppContext, cmd: DeleteReviewCommand) -> Result<(), D tracing::warn!("failed to publish ReviewDeleted: {e}"); } - let history = ctx.repos.diary.get_review_history(&movie_id).await?; + let history = deps.diary.get_review_history(&movie_id).await?; if history.viewings().is_empty() { let poster_path = history.movie().poster_path().cloned(); - ctx.repos.movie.delete_movie(&movie_id).await?; + deps.movie.delete_movie(&movie_id).await?; // best-effort: movie is already deleted, so publish failure is non-fatal - if let Err(e) = ctx - .services + if let Err(e) = deps .event_publisher .publish(&DomainEvent::MovieDeleted { movie_id, diff --git a/crates/application/src/diary/deps.rs b/crates/application/src/diary/deps.rs new file mode 100644 index 0000000..a19064d --- /dev/null +++ b/crates/application/src/diary/deps.rs @@ -0,0 +1,27 @@ +use std::sync::Arc; + +use domain::ports::{ + DiaryRepository, EventPublisher, MovieProfileRepository, MovieRepository, ReviewRepository, + SocialQueryPort, +}; + +use crate::config::AppConfig; + +pub struct DeleteReviewDeps { + pub review: Arc, + pub diary: Arc, + pub movie: Arc, + pub event_publisher: Arc, +} + +pub struct GetMovieSocialPageDeps { + pub movie: Arc, + pub diary: Arc, + pub movie_profile: Arc, +} + +pub struct GetActivityFeedDeps { + pub diary: Arc, + pub social_query: Arc, + pub config: AppConfig, +} diff --git a/crates/application/src/diary/export_diary.rs b/crates/application/src/diary/export_diary.rs index 02098df..e904ecc 100644 --- a/crates/application/src/diary/export_diary.rs +++ b/crates/application/src/diary/export_diary.rs @@ -1,15 +1,20 @@ -use domain::{errors::DomainError, value_objects::UserId}; +use std::sync::Arc; -use crate::{context::AppContext, diary::queries::ExportQuery}; +use domain::{ + errors::DomainError, + ports::{DiaryExporter, DiaryRepository}, + value_objects::UserId, +}; -pub async fn execute(ctx: &AppContext, query: ExportQuery) -> Result, DomainError> { - let entries = ctx - .repos - .diary +use crate::diary::queries::ExportQuery; + +pub async fn execute( + diary: &Arc, + diary_exporter: &Arc, + query: ExportQuery, +) -> Result, DomainError> { + let entries = diary .get_user_history(&UserId::from_uuid(query.user_id)) .await?; - ctx.services - .diary_exporter - .serialize_entries(&entries, query.format) - .await + diary_exporter.serialize_entries(&entries, query.format).await } diff --git a/crates/application/src/diary/get_activity_feed.rs b/crates/application/src/diary/get_activity_feed.rs index 5bff643..9e50da8 100644 --- a/crates/application/src/diary/get_activity_feed.rs +++ b/crates/application/src/diary/get_activity_feed.rs @@ -1,4 +1,4 @@ -use crate::{context::AppContext, diary::queries::GetActivityFeedQuery}; +use crate::diary::{deps::GetActivityFeedDeps, queries::GetActivityFeedQuery}; use domain::{ errors::DomainError, models::{ @@ -9,15 +9,14 @@ use domain::{ }; pub async fn execute( - ctx: &AppContext, + deps: &GetActivityFeedDeps, query: GetActivityFeedQuery, ) -> Result, DomainError> { let page = PageParams::new(Some(query.limit), Some(query.offset))?; - let following = build_following_filter(ctx, &query).await; + let following = build_following_filter(deps, &query).await; - ctx.repos - .diary + deps.diary .query_activity_feed_filtered( &page, &query.sort_by, @@ -28,15 +27,14 @@ pub async fn execute( } async fn build_following_filter( - ctx: &AppContext, + deps: &GetActivityFeedDeps, query: &GetActivityFeedQuery, ) -> Option { if !query.filter_following { return None; } let viewer_id = query.viewer_user_id?; - let urls = ctx - .repos + let urls = deps .social_query .get_accepted_following_urls(viewer_id) .await @@ -47,7 +45,7 @@ async fn build_following_filter( remote_actor_urls: vec![], }); } - let base_url = &ctx.config.base_url; + let base_url = &deps.config.base_url; let mut local_ids = vec![viewer_id]; let mut remote_urls = Vec::new(); for url in urls { diff --git a/crates/application/src/diary/get_diary.rs b/crates/application/src/diary/get_diary.rs index 5d26f79..b877aed 100644 --- a/crates/application/src/diary/get_diary.rs +++ b/crates/application/src/diary/get_diary.rs @@ -1,16 +1,19 @@ +use std::sync::Arc; + use domain::{ errors::DomainError, models::{ DiaryEntry, DiaryFilter, SortDirection, collections::{PageParams, Paginated}, }, + ports::DiaryRepository, value_objects::{MovieId, UserId}, }; -use crate::{context::AppContext, diary::queries::GetDiaryQuery}; +use crate::diary::queries::GetDiaryQuery; pub async fn execute( - ctx: &AppContext, + diary: &Arc, query: GetDiaryQuery, ) -> Result, DomainError> { let page = PageParams::new(query.limit, query.offset)?; @@ -25,7 +28,7 @@ pub async fn execute( search: None, }; - ctx.repos.diary.query_diary(&filter).await + diary.query_diary(&filter).await } #[cfg(test)] diff --git a/crates/application/src/diary/get_movie_social_page.rs b/crates/application/src/diary/get_movie_social_page.rs index 9e3f42a..ac58eaa 100644 --- a/crates/application/src/diary/get_movie_social_page.rs +++ b/crates/application/src/diary/get_movie_social_page.rs @@ -7,7 +7,7 @@ use domain::{ value_objects::MovieId, }; -use crate::{context::AppContext, diary::queries::GetMovieSocialPageQuery}; +use crate::diary::{deps::GetMovieSocialPageDeps, queries::GetMovieSocialPageQuery}; pub struct MovieSocialPageResult { pub movie: Movie, @@ -17,23 +17,22 @@ pub struct MovieSocialPageResult { } pub async fn execute( - ctx: &AppContext, + deps: &GetMovieSocialPageDeps, query: GetMovieSocialPageQuery, ) -> Result { let movie_id = MovieId::from_uuid(query.movie_id); let page = PageParams::new(Some(query.limit), Some(query.offset))?; - let movie = ctx - .repos + let movie = deps .movie .get_movie_by_id(&movie_id) .await? .ok_or_else(|| DomainError::NotFound(format!("Movie {}", query.movie_id)))?; let (stats, reviews, profile) = tokio::try_join!( - ctx.repos.diary.get_movie_stats(&movie_id), - ctx.repos.diary.get_movie_social_feed(&movie_id, &page), - ctx.repos.movie_profile.get_by_movie_id(&movie_id), + deps.diary.get_movie_stats(&movie_id), + deps.diary.get_movie_social_feed(&movie_id, &page), + deps.movie_profile.get_by_movie_id(&movie_id), )?; Ok(MovieSocialPageResult { diff --git a/crates/application/src/diary/get_review_history.rs b/crates/application/src/diary/get_review_history.rs index b3b515d..e57541e 100644 --- a/crates/application/src/diary/get_review_history.rs +++ b/crates/application/src/diary/get_review_history.rs @@ -1,19 +1,22 @@ +use std::sync::Arc; + use domain::{ errors::DomainError, models::ReviewHistory, + ports::DiaryRepository, services::review_history::{ReviewHistoryAnalyzer, Trend}, value_objects::MovieId, }; -use crate::{context::AppContext, diary::queries::GetReviewHistoryQuery}; +use crate::diary::queries::GetReviewHistoryQuery; pub async fn execute( - ctx: &AppContext, + diary: &Arc, query: GetReviewHistoryQuery, ) -> Result<(ReviewHistory, Trend), DomainError> { let movie_id = MovieId::from_uuid(query.movie_id); - let mut history = ctx.repos.diary.get_review_history(&movie_id).await?; + let mut history = diary.get_review_history(&movie_id).await?; let trend = ReviewHistoryAnalyzer::rating_trend(&history)?; diff --git a/crates/application/src/diary/log_review.rs b/crates/application/src/diary/log_review.rs index 01f1aea..ab965ad 100644 --- a/crates/application/src/diary/log_review.rs +++ b/crates/application/src/diary/log_review.rs @@ -1,9 +1,14 @@ +use std::sync::Arc; + use domain::errors::DomainError; -use crate::{context::AppContext, diary::commands::LogReviewCommand}; +use crate::{diary::commands::LogReviewCommand, ports::ReviewLogger}; -pub async fn execute(ctx: &AppContext, cmd: LogReviewCommand) -> Result<(), DomainError> { - ctx.services.review_logger.log_review(cmd).await +pub async fn execute( + review_logger: &Arc, + cmd: LogReviewCommand, +) -> Result<(), DomainError> { + review_logger.log_review(cmd).await } #[cfg(test)] diff --git a/crates/application/src/diary/mod.rs b/crates/application/src/diary/mod.rs index 3faa83e..78564f5 100644 --- a/crates/application/src/diary/mod.rs +++ b/crates/application/src/diary/mod.rs @@ -1,5 +1,6 @@ pub mod commands; pub mod delete_review; +pub mod deps; pub mod export_diary; pub mod get_activity_feed; pub mod get_diary; diff --git a/crates/application/src/diary/tests/delete_review.rs b/crates/application/src/diary/tests/delete_review.rs index 7b00439..404a9ff 100644 --- a/crates/application/src/diary/tests/delete_review.rs +++ b/crates/application/src/diary/tests/delete_review.rs @@ -12,7 +12,9 @@ use domain::{ }; use crate::{ - diary::commands::DeleteReviewCommand, diary::delete_review, test_helpers::TestContextBuilder, + diary::commands::DeleteReviewCommand, + diary::delete_review, + diary::deps::DeleteReviewDeps, }; fn make_movie() -> Movie { @@ -51,15 +53,15 @@ async fn test_delete_review_removes_it() { reviews.save_review(&review).await.unwrap(); diary.seed_history(movie.clone(), vec![]); - let ctx = TestContextBuilder::new() - .with_movies(Arc::clone(&movies) as _) - .with_reviews(Arc::clone(&reviews) as _) - .with_diary(Arc::clone(&diary) as _) - .with_event_publisher(Arc::clone(&events) as _) - .build(); + let deps = DeleteReviewDeps { + review: Arc::clone(&reviews) as _, + diary: diary.clone() as _, + movie: Arc::clone(&movies) as _, + event_publisher: Arc::clone(&events) as _, + }; delete_review::execute( - &ctx, + &deps, DeleteReviewCommand { review_id: review.id().value(), requesting_user_id: user_id.value(), @@ -78,6 +80,9 @@ async fn test_delete_review_removes_it() { #[tokio::test] async fn test_delete_review_wrong_user_is_unauthorized() { let reviews = InMemoryReviewRepository::new(); + let diary = FakeDiaryRepository::new(); + let movies = InMemoryMovieRepository::new(); + let events = NoopEventPublisher::new(); let movie_id = MovieId::from_uuid(uuid::Uuid::new_v4()); let owner_id = UserId::from_uuid(uuid::Uuid::new_v4()); @@ -86,12 +91,15 @@ async fn test_delete_review_wrong_user_is_unauthorized() { reviews.save_review(&review).await.unwrap(); - let ctx = TestContextBuilder::new() - .with_reviews(Arc::clone(&reviews) as _) - .build(); + let deps = DeleteReviewDeps { + review: Arc::clone(&reviews) as _, + diary: diary as _, + movie: movies as _, + event_publisher: Arc::clone(&events) as _, + }; let result = delete_review::execute( - &ctx, + &deps, DeleteReviewCommand { review_id: review.id().value(), requesting_user_id: other_id, diff --git a/crates/application/src/diary/tests/get_activity_feed.rs b/crates/application/src/diary/tests/get_activity_feed.rs index 38a32f7..e498611 100644 --- a/crates/application/src/diary/tests/get_activity_feed.rs +++ b/crates/application/src/diary/tests/get_activity_feed.rs @@ -2,18 +2,30 @@ use std::sync::Arc; use async_trait::async_trait; use domain::errors::DomainError; +use domain::testing::{FakeDiaryRepository, NoopSocialQueryPort}; use crate::{ - diary::get_activity_feed, diary::queries::GetActivityFeedQuery, + config::AppConfig, + diary::deps::GetActivityFeedDeps, + diary::get_activity_feed, + diary::queries::GetActivityFeedQuery, test_helpers::TestContextBuilder, }; +fn default_deps() -> GetActivityFeedDeps { + GetActivityFeedDeps { + diary: FakeDiaryRepository::new() as _, + social_query: Arc::new(NoopSocialQueryPort), + config: TestContextBuilder::new().config, + } +} + #[tokio::test] async fn returns_empty_feed() { - let ctx = TestContextBuilder::new().build(); + let deps = default_deps(); let result = get_activity_feed::execute( - &ctx, + &deps, GetActivityFeedQuery { limit: 10, offset: 0, @@ -32,12 +44,12 @@ async fn returns_empty_feed() { #[tokio::test] async fn returns_feed_with_following_filter() { - let ctx = TestContextBuilder::new().build(); + let deps = default_deps(); let viewer = uuid::Uuid::new_v4(); let result = get_activity_feed::execute( - &ctx, + &deps, GetActivityFeedQuery { limit: 10, offset: 0, @@ -93,12 +105,24 @@ async fn following_filter_parses_local_and_remote_urls() { let social = Arc::new(FakeSocialWithFollowing(following_urls)); - let ctx = TestContextBuilder::new() - .with_social_query(social as _) - .build(); + let deps = GetActivityFeedDeps { + diary: FakeDiaryRepository::new() as _, + social_query: social as _, + config: AppConfig { + allow_registration: true, + base_url: "http://localhost:3000".into(), + rate_limit: 20, + refresh_ttl_seconds: 2_592_000, + wrapup: crate::config::WrapUpConfig { + font_path: None, + logo_path: None, + bg_dir: None, + }, + }, + }; let result = get_activity_feed::execute( - &ctx, + &deps, GetActivityFeedQuery { limit: 10, offset: 0, @@ -118,10 +142,10 @@ async fn following_filter_parses_local_and_remote_urls() { #[tokio::test] async fn following_filter_without_viewer_returns_none() { - let ctx = TestContextBuilder::new().build(); + let deps = default_deps(); let result = get_activity_feed::execute( - &ctx, + &deps, GetActivityFeedQuery { limit: 10, offset: 0, diff --git a/crates/application/src/diary/tests/get_diary.rs b/crates/application/src/diary/tests/get_diary.rs index 4390039..47fcaf8 100644 --- a/crates/application/src/diary/tests/get_diary.rs +++ b/crates/application/src/diary/tests/get_diary.rs @@ -1,11 +1,14 @@ -use crate::{diary::get_diary, diary::queries::GetDiaryQuery, test_helpers::TestContextBuilder}; +use domain::testing::FakeDiaryRepository; +use std::sync::Arc; + +use crate::{diary::get_diary, diary::queries::GetDiaryQuery}; #[tokio::test] async fn returns_empty_page() { - let ctx = TestContextBuilder::new().build(); + let diary = FakeDiaryRepository::new() as Arc; let result = get_diary::execute( - &ctx, + &diary, GetDiaryQuery { limit: None, offset: None, diff --git a/crates/application/src/diary/tests/get_movie_social_page.rs b/crates/application/src/diary/tests/get_movie_social_page.rs index 3063787..849c57f 100644 --- a/crates/application/src/diary/tests/get_movie_social_page.rs +++ b/crates/application/src/diary/tests/get_movie_social_page.rs @@ -5,21 +5,26 @@ use uuid::Uuid; use domain::{ models::Movie, ports::MovieRepository, - testing::InMemoryMovieRepository, + testing::{FakeDiaryRepository, InMemoryMovieProfileRepository, InMemoryMovieRepository}, value_objects::{MovieTitle, ReleaseYear}, }; use crate::{ - diary::get_movie_social_page, diary::queries::GetMovieSocialPageQuery, - test_helpers::TestContextBuilder, + diary::deps::GetMovieSocialPageDeps, + diary::get_movie_social_page, + diary::queries::GetMovieSocialPageQuery, }; #[tokio::test] async fn fails_when_movie_not_found() { - let ctx = TestContextBuilder::new().build(); + let deps = GetMovieSocialPageDeps { + movie: InMemoryMovieRepository::new(), + diary: FakeDiaryRepository::new() as _, + movie_profile: InMemoryMovieProfileRepository::new(), + }; let result = get_movie_social_page::execute( - &ctx, + &deps, GetMovieSocialPageQuery { movie_id: Uuid::new_v4(), limit: 10, @@ -45,12 +50,14 @@ async fn returns_movie_social_page() { let movie_uuid = movie.id().value(); movies.upsert_movie(&movie).await.unwrap(); - let ctx = TestContextBuilder::new() - .with_movies(Arc::clone(&movies) as _) - .build(); + let deps = GetMovieSocialPageDeps { + movie: Arc::clone(&movies) as _, + diary: FakeDiaryRepository::new() as _, + movie_profile: InMemoryMovieProfileRepository::new(), + }; let result = get_movie_social_page::execute( - &ctx, + &deps, GetMovieSocialPageQuery { movie_id: movie_uuid, limit: 10, diff --git a/crates/application/src/diary/tests/get_review_history.rs b/crates/application/src/diary/tests/get_review_history.rs index dfbe38f..da7043c 100644 --- a/crates/application/src/diary/tests/get_review_history.rs +++ b/crates/application/src/diary/tests/get_review_history.rs @@ -1,13 +1,13 @@ +use std::sync::Arc; + use domain::{ models::Movie, + ports::DiaryRepository, services::review_history::Trend, value_objects::{MovieTitle, ReleaseYear}, }; -use crate::{ - diary::get_review_history, diary::queries::GetReviewHistoryQuery, - test_helpers::TestContextBuilder, -}; +use crate::{diary::get_review_history, diary::queries::GetReviewHistoryQuery}; #[tokio::test] async fn returns_empty_history() { @@ -22,10 +22,9 @@ async fn returns_empty_history() { let diary = domain::testing::FakeDiaryRepository::new(); diary.seed_history(movie, vec![]); + let diary: Arc = diary; - let ctx = TestContextBuilder::new().with_diary(diary as _).build(); - - let (history, trend) = get_review_history::execute(&ctx, GetReviewHistoryQuery { movie_id }) + let (history, trend) = get_review_history::execute(&diary, GetReviewHistoryQuery { movie_id }) .await .unwrap(); diff --git a/crates/application/src/diary/tests/log_review.rs b/crates/application/src/diary/tests/log_review.rs index 39f6363..63bf619 100644 --- a/crates/application/src/diary/tests/log_review.rs +++ b/crates/application/src/diary/tests/log_review.rs @@ -17,24 +17,18 @@ use crate::{ test_helpers::TestContextBuilder, }; -fn build_ctx_with_real_logger( +fn build_logger( movies: &Arc, reviews: &Arc, events: &Arc, -) -> crate::context::AppContext { - let logger = Arc::new(DefaultReviewLogger::new( +) -> Arc { + Arc::new(DefaultReviewLogger::new( Arc::clone(movies) as _, Arc::clone(reviews) as _, - crate::test_helpers::TestContextBuilder::new().watchlist_repo, + TestContextBuilder::new().watchlist_repo, Arc::new(domain::testing::FakeMetadataClient) as _, Arc::clone(events) as _, - )); - TestContextBuilder::new() - .with_movies(Arc::clone(movies) as _) - .with_reviews(Arc::clone(reviews) as _) - .with_event_publisher(Arc::clone(events) as _) - .with_review_logger(logger) - .build() + )) } fn movie_input_manual(title: &str, year: u16) -> MovieInput { @@ -62,7 +56,7 @@ async fn test_log_review_creates_movie_and_review() { let movies = InMemoryMovieRepository::new(); let reviews = InMemoryReviewRepository::new(); let events = NoopEventPublisher::new(); - let ctx = build_ctx_with_real_logger(&movies, &reviews, &events); + let logger = build_logger(&movies, &reviews, &events); let user_id = uuid::Uuid::new_v4(); let cmd = LogReviewCommand { @@ -73,7 +67,7 @@ async fn test_log_review_creates_movie_and_review() { watched_at: Utc::now().naive_utc(), }; - log_review::execute(&ctx, cmd).await.unwrap(); + log_review::execute(&logger, cmd).await.unwrap(); assert_eq!(reviews.count(), 1, "review should be saved"); assert!(!events.published().is_empty(), "events should be published"); @@ -95,7 +89,7 @@ async fn test_log_review_reuses_existing_movie() { movies.upsert_movie(&existing_movie).await.unwrap(); let events = NoopEventPublisher::new(); - let ctx = build_ctx_with_real_logger(&movies, &reviews, &events); + let logger = build_logger(&movies, &reviews, &events); let cmd = LogReviewCommand { user_id: uuid::Uuid::new_v4(), @@ -105,7 +99,7 @@ async fn test_log_review_reuses_existing_movie() { watched_at: Utc::now().naive_utc(), }; - log_review::execute(&ctx, cmd).await.unwrap(); + log_review::execute(&logger, cmd).await.unwrap(); assert_eq!(movies.count(), 1, "no duplicate movie"); assert_eq!(reviews.count(), 1); @@ -116,7 +110,8 @@ async fn test_log_review_with_invalid_rating_fails() { let movies = InMemoryMovieRepository::new(); let reviews = InMemoryReviewRepository::new(); let events = NoopEventPublisher::new(); - let ctx = build_ctx_with_real_logger(&movies, &reviews, &events); + let logger = build_logger(&movies, &reviews, &events); + let cmd = LogReviewCommand { user_id: uuid::Uuid::new_v4(), input: movie_input_manual("Some Film", 2000), @@ -124,6 +119,6 @@ async fn test_log_review_with_invalid_rating_fails() { comment: None, watched_at: Utc::now().naive_utc(), }; - let result = log_review::execute(&ctx, cmd).await; + let result = log_review::execute(&logger, cmd).await; assert!(result.is_err(), "rating > 5 should fail"); } diff --git a/crates/presentation/src/handlers/diary.rs b/crates/presentation/src/handlers/diary.rs index 8854be9..35a3af5 100644 --- a/crates/presentation/src/handlers/diary.rs +++ b/crates/presentation/src/handlers/diary.rs @@ -11,6 +11,7 @@ use application::diary::{ delete_review, export_diary as export_diary_uc, get_activity_feed as get_feed_uc, get_diary, log_review, queries::{ExportQuery, GetActivityFeedQuery}, + deps::{DeleteReviewDeps, GetActivityFeedDeps}, }; use domain::models::ExportFormat; @@ -50,7 +51,7 @@ pub async fn get_diary( State(state): State, Query(params): Query, ) -> Result, ApiError> { - let page = get_diary::execute(&state.app_ctx, to_diary_query(params)).await?; + let page = get_diary::execute(&state.app_ctx.repos.diary, to_diary_query(params)).await?; Ok(Json(DiaryResponse { items: page @@ -80,7 +81,7 @@ pub async fn post_review( Json(req): Json, ) -> Result { let data = LogReviewData::try_from(req).map_err(ApiError)?; - log_review::execute(&state.app_ctx, data.into_command(user.0.value())).await?; + log_review::execute(&state.app_ctx.services.review_logger, data.into_command(user.0.value())).await?; Ok(StatusCode::CREATED) } @@ -104,7 +105,13 @@ pub async fn delete_review( review_id, requesting_user_id: user_id.value(), }; - delete_review::execute(&state.app_ctx, cmd).await?; + let deps = DeleteReviewDeps { + review: state.app_ctx.repos.review.clone(), + diary: state.app_ctx.repos.diary.clone(), + movie: state.app_ctx.repos.movie.clone(), + event_publisher: state.app_ctx.services.event_publisher.clone(), + }; + delete_review::execute(&deps, cmd).await?; Ok(StatusCode::NO_CONTENT) } @@ -136,7 +143,13 @@ pub async fn export_diary( user_id: user.0.value(), format, }; - match export_diary_uc::execute(&state.app_ctx, query).await { + match export_diary_uc::execute( + &state.app_ctx.repos.diary, + &state.app_ctx.services.diary_exporter, + query, + ) + .await + { Ok(bytes) => ( StatusCode::OK, [ @@ -165,8 +178,13 @@ pub async fn get_activity_feed( State(state): State, Query(params): Query, ) -> Result, ApiError> { + let deps = GetActivityFeedDeps { + diary: state.app_ctx.repos.diary.clone(), + social_query: state.app_ctx.repos.social_query.clone(), + config: state.app_ctx.config.clone(), + }; let page = get_feed_uc::execute( - &state.app_ctx, + &deps, GetActivityFeedQuery { limit: params.limit.unwrap_or(20), offset: params.offset.unwrap_or(0), @@ -226,7 +244,7 @@ pub async fn post_review_html( } }; - match log_review::execute(&state.app_ctx, data.into_command(user_id.value())).await { + match log_review::execute(&state.app_ctx.services.review_logger, data.into_command(user_id.value())).await { Ok(_) => Redirect::to("/").into_response(), Err(e) => { let msg = encode_error(&e.to_string()); @@ -249,7 +267,13 @@ pub async fn post_delete_review_html( review_id, requesting_user_id: user_id.value(), }; - match delete_review::execute(&state.app_ctx, cmd).await { + let deps = DeleteReviewDeps { + review: state.app_ctx.repos.review.clone(), + diary: state.app_ctx.repos.diary.clone(), + movie: state.app_ctx.repos.movie.clone(), + event_publisher: state.app_ctx.services.event_publisher.clone(), + }; + match delete_review::execute(&deps, cmd).await { Ok(()) => { let redirect_url = form .redirect_after @@ -281,7 +305,13 @@ pub async fn get_export_html( user_id: user_id.value(), format, }; - match export_diary_uc::execute(&state.app_ctx, query).await { + match export_diary_uc::execute( + &state.app_ctx.repos.diary, + &state.app_ctx.services.diary_exporter, + query, + ) + .await + { Ok(bytes) => ( StatusCode::OK, [ @@ -332,7 +362,13 @@ pub async fn get_activity_feed_html( filter_following, }; - match application::diary::get_activity_feed::execute(&state.app_ctx, query).await { + let deps = GetActivityFeedDeps { + diary: state.app_ctx.repos.diary.clone(), + social_query: state.app_ctx.repos.social_query.clone(), + config: state.app_ctx.config.clone(), + }; + + match application::diary::get_activity_feed::execute(&deps, query).await { Ok(entries) => { let entry_limit = entries.limit; let entry_offset = entries.offset; diff --git a/crates/presentation/src/handlers/movies.rs b/crates/presentation/src/handlers/movies.rs index 6c9b44c..5443c76 100644 --- a/crates/presentation/src/handlers/movies.rs +++ b/crates/presentation/src/handlers/movies.rs @@ -9,6 +9,7 @@ use uuid::Uuid; use application::{ diary::{ commands::SyncPosterCommand, + deps::{GetMovieSocialPageDeps}, get_movie_social_page, get_review_history, queries::{GetMovieSocialPageQuery, GetReviewHistoryQuery}, }, @@ -88,7 +89,7 @@ pub async fn get_review_history( Path(movie_id): Path, ) -> Result, ApiError> { let (history, trend) = - get_review_history::execute(&state.app_ctx, GetReviewHistoryQuery { movie_id }).await?; + get_review_history::execute(&state.app_ctx.repos.diary, GetReviewHistoryQuery { movie_id }).await?; Ok(Json(ReviewHistoryResponse { movie: crate::mappers::movies::movie_to_dto(history.movie()), @@ -154,7 +155,11 @@ pub async fn get_movie_detail( let offset = params.offset.unwrap_or(0); let result = get_movie_social_page::execute( - &state.app_ctx, + &GetMovieSocialPageDeps { + movie: state.app_ctx.repos.movie.clone(), + diary: state.app_ctx.repos.diary.clone(), + movie_profile: state.app_ctx.repos.movie_profile.clone(), + }, GetMovieSocialPageQuery { movie_id, limit, @@ -288,7 +293,11 @@ pub async fn get_movie_detail_html( let offset = params.offset.unwrap_or(0); match get_movie_social_page::execute( - &state.app_ctx, + &GetMovieSocialPageDeps { + movie: state.app_ctx.repos.movie.clone(), + diary: state.app_ctx.repos.diary.clone(), + movie_profile: state.app_ctx.repos.movie_profile.clone(), + }, GetMovieSocialPageQuery { movie_id, limit, diff --git a/crates/presentation/src/handlers/rss.rs b/crates/presentation/src/handlers/rss.rs index 31c1239..d05cedd 100644 --- a/crates/presentation/src/handlers/rss.rs +++ b/crates/presentation/src/handlers/rss.rs @@ -18,7 +18,7 @@ pub async fn get_feed(State(state): State) -> Result