This commit is contained in:
@@ -13,34 +13,44 @@ use domain::ports::{RemoteWatchlistRepository, SocialQueryPort};
|
||||
use crate::config::AppConfig;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppContext {
|
||||
pub movie_repository: Arc<dyn MovieRepository>,
|
||||
pub review_repository: Arc<dyn ReviewRepository>,
|
||||
pub diary_repository: Arc<dyn DiaryRepository>,
|
||||
pub diary_exporter: Arc<dyn DiaryExporter>,
|
||||
pub document_parser: Arc<dyn DocumentParser>,
|
||||
pub stats_repository: Arc<dyn StatsRepository>,
|
||||
pub metadata_client: Arc<dyn MetadataClient>,
|
||||
pub poster_fetcher: Arc<dyn PosterFetcherClient>,
|
||||
pub image_storage: Arc<dyn ImageStorage>,
|
||||
pub event_publisher: Arc<dyn EventPublisher>,
|
||||
pub auth_service: Arc<dyn AuthService>,
|
||||
pub password_hasher: Arc<dyn PasswordHasher>,
|
||||
pub user_repository: Arc<dyn UserRepository>,
|
||||
pub import_session_repository: Arc<dyn ImportSessionRepository>,
|
||||
pub import_profile_repository: Arc<dyn ImportProfileRepository>,
|
||||
pub movie_profile_repository: Arc<dyn MovieProfileRepository>,
|
||||
pub struct Repositories {
|
||||
pub movie: Arc<dyn MovieRepository>,
|
||||
pub review: Arc<dyn ReviewRepository>,
|
||||
pub diary: Arc<dyn DiaryRepository>,
|
||||
pub stats: Arc<dyn StatsRepository>,
|
||||
pub user: Arc<dyn UserRepository>,
|
||||
pub import_session: Arc<dyn ImportSessionRepository>,
|
||||
pub import_profile: Arc<dyn ImportProfileRepository>,
|
||||
pub movie_profile: Arc<dyn MovieProfileRepository>,
|
||||
pub watchlist: Arc<dyn WatchlistRepository>,
|
||||
pub watch_event: Arc<dyn WatchEventRepository>,
|
||||
pub webhook_token: Arc<dyn WebhookTokenRepository>,
|
||||
pub person_command: Arc<dyn PersonCommand>,
|
||||
pub person_query: Arc<dyn PersonQuery>,
|
||||
pub search_port: Arc<dyn SearchPort>,
|
||||
pub search_command: Arc<dyn SearchCommand>,
|
||||
pub watchlist_repository: Arc<dyn WatchlistRepository>,
|
||||
pub watch_event_repository: Arc<dyn WatchEventRepository>,
|
||||
pub webhook_token_repository: Arc<dyn WebhookTokenRepository>,
|
||||
pub profile_fields_repository: Arc<dyn UserProfileFieldsRepository>,
|
||||
pub profile_fields: Arc<dyn UserProfileFieldsRepository>,
|
||||
#[cfg(feature = "federation")]
|
||||
pub remote_watchlist_repository: Arc<dyn RemoteWatchlistRepository>,
|
||||
pub remote_watchlist: Arc<dyn RemoteWatchlistRepository>,
|
||||
#[cfg(feature = "federation")]
|
||||
pub social_query: Arc<dyn SocialQueryPort>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Services {
|
||||
pub auth: Arc<dyn AuthService>,
|
||||
pub password_hasher: Arc<dyn PasswordHasher>,
|
||||
pub metadata: Arc<dyn MetadataClient>,
|
||||
pub poster_fetcher: Arc<dyn PosterFetcherClient>,
|
||||
pub image_storage: Arc<dyn ImageStorage>,
|
||||
pub event_publisher: Arc<dyn EventPublisher>,
|
||||
pub diary_exporter: Arc<dyn DiaryExporter>,
|
||||
pub document_parser: Arc<dyn DocumentParser>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppContext {
|
||||
pub repos: Repositories,
|
||||
pub services: Services,
|
||||
pub config: AppConfig,
|
||||
}
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
use uuid::Uuid;
|
||||
|
||||
use domain::models::{
|
||||
DiaryEntry, FeedEntry, MonthActivity, Movie, MovieProfile, MovieStats, UserStats, UserSummary,
|
||||
UserTrends, collections::Paginated,
|
||||
};
|
||||
|
||||
pub struct RemoteActorView {
|
||||
pub handle: String,
|
||||
pub display_name: Option<String>,
|
||||
pub url: String,
|
||||
pub avatar_url: Option<String>,
|
||||
}
|
||||
use domain::models::DiaryEntry;
|
||||
|
||||
pub struct HtmlPageContext {
|
||||
pub user_email: Option<String>,
|
||||
@@ -30,239 +20,16 @@ impl HtmlPageContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoginPageData<'a> {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub error: Option<&'a str>,
|
||||
}
|
||||
|
||||
pub struct RegisterPageData<'a> {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub error: Option<&'a str>,
|
||||
}
|
||||
|
||||
pub struct NewReviewPageData<'a> {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub error: Option<&'a str>,
|
||||
}
|
||||
|
||||
pub struct ActivityFeedPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub entries: Paginated<FeedEntry>,
|
||||
pub current_offset: u32,
|
||||
pub has_more: bool,
|
||||
pub limit: u32,
|
||||
pub filter: String,
|
||||
pub sort_by: String,
|
||||
pub search: String,
|
||||
}
|
||||
|
||||
pub struct UsersPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub users: Vec<UserSummary>,
|
||||
pub remote_actors: Vec<RemoteActorView>,
|
||||
}
|
||||
|
||||
pub struct ProfilePageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub profile_user_id: Uuid,
|
||||
pub profile_user_email: String,
|
||||
pub stats: UserStats,
|
||||
pub view: String,
|
||||
pub entries: Option<Paginated<DiaryEntry>>,
|
||||
pub current_offset: u32,
|
||||
pub has_more: bool,
|
||||
pub limit: u32,
|
||||
pub history: Option<Vec<MonthActivity>>,
|
||||
pub trends: Option<UserTrends>,
|
||||
pub is_own_profile: bool,
|
||||
pub error: Option<String>,
|
||||
pub following_count: usize,
|
||||
pub followers_count: usize,
|
||||
pub pending_followers: Vec<RemoteActorView>,
|
||||
pub sort_by: String,
|
||||
pub search: String,
|
||||
}
|
||||
|
||||
pub struct FollowingPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub user_id: Uuid,
|
||||
pub actors: Vec<RemoteActorView>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub struct FollowersPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub user_id: Uuid,
|
||||
pub actors: Vec<RemoteActorView>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub struct MovieDetailPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub movie: Movie,
|
||||
pub stats: MovieStats,
|
||||
pub reviews: Paginated<FeedEntry>,
|
||||
pub profile: Option<MovieProfile>,
|
||||
pub on_watchlist: bool,
|
||||
pub current_offset: u32,
|
||||
pub has_more: bool,
|
||||
pub limit: u32,
|
||||
pub histogram_max: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WatchlistDisplayEntry {
|
||||
/// Always a full URL: /images/{path} for local, https://... for remote
|
||||
pub poster_url: Option<String>,
|
||||
pub movie_title: String,
|
||||
pub release_year: u16,
|
||||
/// /movies/{id} for local; None for remote entries without a local movie record
|
||||
pub movie_url: Option<String>,
|
||||
pub added_at: String,
|
||||
/// /watchlist/{movie_id}/remove for owner; None for remote or non-owner
|
||||
pub remove_url: Option<String>,
|
||||
}
|
||||
|
||||
pub struct WatchlistPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub owner_id: uuid::Uuid,
|
||||
pub display_entries: Vec<WatchlistDisplayEntry>,
|
||||
pub current_offset: u32,
|
||||
pub has_more: bool,
|
||||
pub limit: u32,
|
||||
pub is_owner: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub struct ImportUploadPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub profiles: Vec<ImportProfileView>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub struct ImportProfileView {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub struct ImportMappingPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub session_id: String,
|
||||
pub columns: Vec<String>,
|
||||
pub sample_rows: Vec<Vec<String>>,
|
||||
pub domain_fields: Vec<(&'static str, &'static str)>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub struct ImportPreviewRow {
|
||||
pub index: usize,
|
||||
pub status: ImportRowStatus,
|
||||
pub cells: Vec<String>,
|
||||
}
|
||||
|
||||
pub enum ImportRowStatus {
|
||||
Valid,
|
||||
Duplicate,
|
||||
Invalid(String),
|
||||
}
|
||||
|
||||
pub struct ImportPreviewPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub session_id: String,
|
||||
pub columns: Vec<String>,
|
||||
pub rows: Vec<ImportPreviewRow>,
|
||||
}
|
||||
|
||||
pub struct ProfileSettingsPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub bio: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
pub banner_url: Option<String>,
|
||||
pub also_known_as: Option<String>,
|
||||
pub profile_fields: Vec<(String, String)>,
|
||||
pub saved: bool,
|
||||
}
|
||||
|
||||
pub struct BlockedDomainEntry {
|
||||
pub domain: String,
|
||||
pub reason: Option<String>,
|
||||
pub blocked_at: String,
|
||||
}
|
||||
|
||||
pub struct BlockedDomainsPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub domains: Vec<BlockedDomainEntry>,
|
||||
}
|
||||
|
||||
pub struct BlockedActorEntry {
|
||||
pub url: String,
|
||||
pub handle: String,
|
||||
pub display_name: Option<String>,
|
||||
pub avatar_url: Option<String>,
|
||||
}
|
||||
|
||||
pub struct BlockedActorsPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub actors: Vec<BlockedActorEntry>,
|
||||
}
|
||||
|
||||
pub struct WebhookTokenView {
|
||||
pub id: String,
|
||||
pub provider: String,
|
||||
pub label: Option<String>,
|
||||
pub created_at: String,
|
||||
pub last_used_at: Option<String>,
|
||||
}
|
||||
|
||||
pub struct IntegrationsPageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub tokens: Vec<WebhookTokenView>,
|
||||
pub webhook_base_url: String,
|
||||
pub new_token: Option<String>,
|
||||
}
|
||||
|
||||
pub struct WatchQueueDisplayEntry {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub year: Option<u16>,
|
||||
pub source: String,
|
||||
pub watched_at: String,
|
||||
pub movie_url: Option<String>,
|
||||
}
|
||||
|
||||
pub struct WatchQueuePageData {
|
||||
pub ctx: HtmlPageContext,
|
||||
pub entries: Vec<WatchQueueDisplayEntry>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
pub trait HtmlRenderer: Send + Sync {
|
||||
fn render_diary_page(
|
||||
&self,
|
||||
data: &Paginated<DiaryEntry>,
|
||||
ctx: HtmlPageContext,
|
||||
) -> Result<String, String>;
|
||||
fn render_login_page(&self, data: LoginPageData<'_>) -> Result<String, String>;
|
||||
fn render_register_page(&self, data: RegisterPageData<'_>) -> Result<String, String>;
|
||||
fn render_new_review_page(&self, data: NewReviewPageData<'_>) -> Result<String, String>;
|
||||
fn render_activity_feed_page(&self, data: ActivityFeedPageData) -> Result<String, String>;
|
||||
fn render_users_page(&self, data: UsersPageData) -> Result<String, String>;
|
||||
fn render_profile_page(&self, data: ProfilePageData) -> Result<String, String>;
|
||||
fn render_following_page(&self, data: FollowingPageData) -> Result<String, String>;
|
||||
fn render_followers_page(&self, data: FollowersPageData) -> Result<String, String>;
|
||||
fn render_movie_detail_page(&self, data: MovieDetailPageData) -> Result<String, String>;
|
||||
fn render_import_upload_page(&self, data: ImportUploadPageData) -> Result<String, String>;
|
||||
fn render_import_mapping_page(&self, data: ImportMappingPageData) -> Result<String, String>;
|
||||
fn render_import_preview_page(&self, data: ImportPreviewPageData) -> Result<String, String>;
|
||||
fn render_profile_settings_page(&self, data: ProfileSettingsPageData)
|
||||
-> Result<String, String>;
|
||||
fn render_blocked_domains_page(&self, data: BlockedDomainsPageData) -> Result<String, String>;
|
||||
fn render_blocked_actors_page(&self, data: BlockedActorsPageData) -> Result<String, String>;
|
||||
fn render_watchlist_page(&self, data: WatchlistPageData) -> Result<String, String>;
|
||||
fn render_integrations_page(&self, data: IntegrationsPageData) -> Result<String, String>;
|
||||
fn render_watch_queue_page(&self, data: WatchQueuePageData) -> Result<String, String>;
|
||||
}
|
||||
|
||||
pub trait RssFeedRenderer: Send + Sync {
|
||||
fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result<String, String>;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ use domain::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{config::AppConfig, context::AppContext};
|
||||
use crate::{
|
||||
config::AppConfig,
|
||||
context::{AppContext, Repositories, Services},
|
||||
};
|
||||
|
||||
pub struct TestContextBuilder {
|
||||
pub movie_repo: Arc<dyn MovieRepository>,
|
||||
@@ -125,35 +128,39 @@ impl TestContextBuilder {
|
||||
|
||||
pub fn build(self) -> AppContext {
|
||||
AppContext {
|
||||
movie_repository: self.movie_repo,
|
||||
review_repository: self.review_repo,
|
||||
diary_repository: self.diary_repo,
|
||||
diary_exporter: self.diary_exporter,
|
||||
document_parser: self.document_parser,
|
||||
stats_repository: self.stats_repo,
|
||||
metadata_client: self.metadata_client,
|
||||
poster_fetcher: self.poster_fetcher,
|
||||
image_storage: self.image_storage,
|
||||
event_publisher: self.event_publisher,
|
||||
auth_service: self.auth_service,
|
||||
password_hasher: self.password_hasher,
|
||||
user_repository: self.user_repo,
|
||||
import_session_repository: self.import_session_repo,
|
||||
import_profile_repository: self.import_profile_repo,
|
||||
movie_profile_repository: self.movie_profile_repo,
|
||||
watchlist_repository: self.watchlist_repo,
|
||||
watch_event_repository: self.watch_event_repo,
|
||||
webhook_token_repository: self.webhook_token_repo,
|
||||
profile_fields_repository: self.profile_fields_repo,
|
||||
person_command: self.person_command,
|
||||
person_query: self.person_query,
|
||||
search_port: self.search_port,
|
||||
search_command: self.search_command,
|
||||
repos: Repositories {
|
||||
movie: self.movie_repo,
|
||||
review: self.review_repo,
|
||||
diary: self.diary_repo,
|
||||
stats: self.stats_repo,
|
||||
user: self.user_repo,
|
||||
import_session: self.import_session_repo,
|
||||
import_profile: self.import_profile_repo,
|
||||
movie_profile: self.movie_profile_repo,
|
||||
watchlist: self.watchlist_repo,
|
||||
watch_event: self.watch_event_repo,
|
||||
webhook_token: self.webhook_token_repo,
|
||||
profile_fields: self.profile_fields_repo,
|
||||
person_command: self.person_command,
|
||||
person_query: self.person_query,
|
||||
search_port: self.search_port,
|
||||
search_command: self.search_command,
|
||||
#[cfg(feature = "federation")]
|
||||
remote_watchlist: Arc::new(PanicRemoteWatchlistRepository),
|
||||
#[cfg(feature = "federation")]
|
||||
social_query: Arc::new(PanicSocialQueryPort),
|
||||
},
|
||||
services: Services {
|
||||
auth: self.auth_service,
|
||||
password_hasher: self.password_hasher,
|
||||
metadata: self.metadata_client,
|
||||
poster_fetcher: self.poster_fetcher,
|
||||
image_storage: self.image_storage,
|
||||
event_publisher: self.event_publisher,
|
||||
diary_exporter: self.diary_exporter,
|
||||
document_parser: self.document_parser,
|
||||
},
|
||||
config: self.config,
|
||||
#[cfg(feature = "federation")]
|
||||
remote_watchlist_repository: std::sync::Arc::new(PanicRemoteWatchlistRepository),
|
||||
#[cfg(feature = "federation")]
|
||||
social_query: std::sync::Arc::new(PanicSocialQueryPort),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user