use paginator_utils::{PaginatorResponse, PaginatorResponseMeta}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use uuid::Uuid; use zod_rs::prelude::*; use crate::materials::domain::{MaterialEntity, MaterialListItem}; use imphnen_libs::ZodValidate; #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, ZodSchema)] #[serde(rename_all = "camelCase")] pub struct CreateMaterialRequest { #[zod(min_length(3), max_length(200))] pub title: String, #[zod(min_length(1), max_length(100))] pub category: String, #[zod(min_length(3), max_length(500))] pub description: String, #[zod(min_length(10))] pub content: String, #[serde(skip_serializing_if = "Option::is_none")] pub cover_url: Option, } impl ZodValidate for CreateMaterialRequest { fn zod_validate(value: &serde_json::Value) -> Result { Self::validate_and_parse(value).map_err(|e| e.to_string()) } } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, ZodSchema)] #[serde(rename_all = "camelCase")] pub struct UpdateMaterialRequest { #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub category: Option, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] pub content: Option, #[serde(skip_serializing_if = "Option::is_none")] pub cover_url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub is_published: Option, } impl ZodValidate for UpdateMaterialRequest { fn zod_validate(value: &serde_json::Value) -> Result { Self::validate_and_parse(value).map_err(|e| e.to_string()) } } #[derive(Serialize, Debug, ToSchema)] #[serde(rename_all = "camelCase")] pub struct MaterialResponse { pub id: Uuid, pub mentor_id: Uuid, pub title: String, pub slug: String, pub category: String, pub description: String, pub content: String, pub cover_url: Option, pub is_published: bool, pub created_at: String, pub updated_at: String, } impl MaterialResponse { pub fn from_entity(e: &MaterialEntity) -> Self { Self { id: e.id, mentor_id: e.mentor_id, title: e.title.clone(), slug: e.slug.clone(), category: e.category.clone(), description: e.description.clone(), content: e.content.clone(), cover_url: e.cover_url.clone(), is_published: e.is_published, created_at: e.created_at.to_rfc3339(), updated_at: e.updated_at.to_rfc3339(), } } } #[derive(Serialize, Debug, ToSchema)] #[serde(rename_all = "camelCase")] pub struct MaterialListItemResponse { pub id: Uuid, pub mentor_id: Uuid, pub title: String, pub slug: String, pub category: String, pub description: String, pub cover_url: Option, pub is_published: bool, pub created_at: String, pub updated_at: String, } impl From<&MaterialEntity> for MaterialListItemResponse { fn from(e: &MaterialEntity) -> Self { Self { id: e.id, mentor_id: e.mentor_id, title: e.title.clone(), slug: e.slug.clone(), category: e.category.clone(), description: e.description.clone(), cover_url: e.cover_url.clone(), is_published: e.is_published, created_at: e.created_at.to_rfc3339(), updated_at: e.updated_at.to_rfc3339(), } } } impl From<&MaterialListItem> for MaterialListItemResponse { fn from(e: &MaterialListItem) -> Self { Self { id: e.id, mentor_id: e.mentor_id, title: e.title.clone(), slug: e.slug.clone(), category: e.category.clone(), description: e.description.clone(), cover_url: e.cover_url.clone(), is_published: e.is_published, created_at: e.created_at.to_rfc3339(), updated_at: e.updated_at.to_rfc3339(), } } } pub type MaterialListResponse = PaginatorResponse;