use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use uuid::Uuid; use super::author::AuthorRef; use super::genre::GenreRef; use super::page_analysis::ContentWarning; use super::patch::Patch; use super::tag::TagRef; #[derive(Debug, Clone, Serialize, Deserialize, FromRow)] pub struct Manga { pub id: Uuid, pub title: String, pub status: String, pub alt_titles: Vec, pub description: Option, pub cover_image_path: Option, pub created_at: DateTime, pub updated_at: DateTime, } /// Shape returned by list endpoints. Cards show the title, authors and /// genres; tags are intentionally elided here to keep the response /// proportional to what a card actually renders. #[derive(Debug, Clone, Serialize)] pub struct MangaCard { #[serde(flatten)] pub manga: Manga, pub authors: Vec, pub genres: Vec, } /// Shape returned by `GET /mangas/:id`. Adds user-added tags on top of /// the card fields, plus the deduped content warnings derived by the /// analysis worker across all the manga's pages. #[derive(Debug, Clone, Serialize)] pub struct MangaDetail { #[serde(flatten)] pub manga: Manga, pub authors: Vec, pub genres: Vec, pub tags: Vec, pub content_warnings: Vec, /// Total bytes of all this manga's stored chapter pages (cover /// excluded), over every chapter. `None` when any page is unmeasured /// (frontend shows an em-dash); `Some(0)` when there are no pages. /// Computed in the DB rather than summed from the chapter list, which /// is paginated and would undercount mangas with many chapters. pub chapter_storage_bytes: Option, } #[derive(Debug, Clone, Deserialize, Default)] pub struct NewManga { pub title: String, #[serde(default)] pub status: Option, /// Author display names. Looked up case-insensitively; created on /// the fly when unseen. #[serde(default)] pub authors: Vec, #[serde(default)] pub description: Option, #[serde(default)] pub alt_titles: Vec, #[serde(default)] pub genre_ids: Vec, } #[derive(Debug, Clone, Deserialize, Default)] pub struct MangaPatch { pub title: Option, pub status: Option, /// Three-state: missing key leaves the description alone; explicit /// `null` clears it; a string sets it. See `Patch` for details. #[serde(default)] pub description: Patch, pub alt_titles: Option>, /// When provided, replaces the manga's authors atomically. pub authors: Option>, /// When provided, replaces the manga's genres atomically. pub genre_ids: Option>, } // `Patch` lives in `super::patch` so other resources (collections, // future PATCH endpoints) can reuse the same three-state semantics // without re-importing through `manga::`.