movie detail page + importer architecture fix

This commit is contained in:
2026-05-10 23:59:26 +02:00
parent f2f1317660
commit b2a2aa4262
49 changed files with 1670 additions and 264 deletions

View File

@@ -0,0 +1,75 @@
use thiserror::Error;
#[derive(Debug, Clone, Default)]
pub struct ParsedFile {
pub columns: Vec<String>,
pub rows: Vec<Vec<String>>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DomainField {
Title,
ReleaseYear,
Director,
Rating,
WatchedAt,
Comment,
ExternalMetadataId,
}
#[derive(Debug, Clone)]
pub enum Transform {
RatingScale(f64),
DateFormat(String),
Identity,
}
#[derive(Debug, Clone)]
pub struct FieldMapping {
pub source_column: String,
pub domain_field: DomainField,
pub transform: Transform,
}
#[derive(Debug, Clone, Default)]
pub struct ImportRow {
pub title: Option<String>,
pub release_year: Option<String>,
pub director: Option<String>,
pub rating: Option<String>,
pub watched_at: Option<String>,
pub comment: Option<String>,
pub external_metadata_id: Option<String>,
}
#[derive(Debug, Clone)]
pub enum RowResult {
Valid(ImportRow),
Invalid { errors: Vec<String>, raw: Vec<(String, String)> },
}
#[derive(Debug, Clone)]
pub struct AnnotatedRow {
pub result: RowResult,
pub is_duplicate: bool,
}
#[derive(Debug, Error)]
pub enum ImportError {
#[error("CSV parse error: {0}")]
Csv(String),
#[error("JSON parse error: {0}")]
Json(String),
#[error("XLSX parse error: {0}")]
Xlsx(String),
#[error("Empty file")]
Empty,
#[error("Missing header row")]
NoHeader,
}
pub enum FileFormat {
Csv,
Json,
Xlsx,
}

View File

@@ -1,17 +1,26 @@
use chrono::NaiveDateTime;
use crate::value_objects::{ImportProfileId, UserId};
use crate::{
models::FieldMapping,
value_objects::{ImportProfileId, UserId},
};
#[derive(Debug, Clone)]
pub struct ImportProfile {
pub id: ImportProfileId,
pub user_id: UserId,
pub name: String,
pub field_mappings: String,
pub field_mappings: Vec<FieldMapping>,
pub created_at: NaiveDateTime,
}
impl ImportProfile {
pub fn new(id: ImportProfileId, user_id: UserId, name: String, field_mappings: String, created_at: NaiveDateTime) -> Self {
pub fn new(
id: ImportProfileId,
user_id: UserId,
name: String,
field_mappings: Vec<FieldMapping>,
created_at: NaiveDateTime,
) -> Self {
Self { id, user_id, name, field_mappings, created_at }
}
}

View File

@@ -1,20 +1,31 @@
use chrono::NaiveDateTime;
use crate::value_objects::{ImportSessionId, UserId};
use crate::{
models::{AnnotatedRow, FieldMapping, ParsedFile},
value_objects::{ImportSessionId, UserId},
};
#[derive(Debug, Clone)]
pub struct ImportSession {
pub id: ImportSessionId,
pub user_id: UserId,
pub parsed_data: String,
pub field_mappings: Option<String>,
pub row_results: Option<String>,
pub parsed_file: Option<ParsedFile>,
pub field_mappings: Option<Vec<FieldMapping>>,
pub row_results: Option<Vec<AnnotatedRow>>,
pub created_at: NaiveDateTime,
pub expires_at: NaiveDateTime,
}
impl ImportSession {
pub fn new(id: ImportSessionId, user_id: UserId, parsed_data: String, created_at: NaiveDateTime) -> Self {
pub fn new(id: ImportSessionId, user_id: UserId, created_at: NaiveDateTime) -> Self {
let expires_at = created_at + chrono::Duration::hours(24);
Self { id, user_id, parsed_data, field_mappings: None, row_results: None, created_at, expires_at }
Self {
id,
user_id,
parsed_file: None,
field_mappings: None,
row_results: None,
created_at,
expires_at,
}
}
}

View File

@@ -9,9 +9,14 @@ use crate::{
},
};
pub mod collections;
pub mod import;
pub mod import_session;
pub mod import_profile;
pub use import::{
AnnotatedRow, DomainField, FieldMapping, FileFormat, ImportError,
ImportRow, ParsedFile, RowResult, Transform,
};
pub use import_session::ImportSession;
pub use import_profile::ImportProfile;
@@ -216,6 +221,10 @@ impl Review {
let r = self.rating.value();
[r >= 1, r >= 2, r >= 3, r >= 4, r >= 5]
}
pub fn is_remote(&self) -> bool {
matches!(self.source, ReviewSource::Remote { .. })
}
}
#[derive(Clone, Debug)]
@@ -259,6 +268,14 @@ impl ReviewHistory {
}
}
#[derive(Clone, Debug)]
pub struct MovieStats {
pub total_count: u64,
pub avg_rating: Option<f64>,
pub federated_count: u64,
pub rating_histogram: [u64; 5], // index 0 = 1★, index 4 = 5★
}
#[derive(Clone, Debug, Default)]
pub enum UserRole {
#[default]