use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use utoipa::{ToSchema, schema}; use validator::Validate; use crate::v1::hackathon::hackathon_schema::{ HackathonEventType, HackathonEventsSchema, HackathonPhase, HackathonSchema, HackathonStatus, HackathonSubmissionsSchema, HackathonTimelineSchema, SubmissionStatus, }; // Hackathon DTOs #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonCreateRequestDto { #[validate(length(min = 1, max = 100, message = "Hackathon name must be between 1 and 100 characters"))] pub name: String, #[validate(length(min = 1, max = 1000, message = "Description must be between 1 and 1000 characters"))] pub description: String, #[schema(value_type = String, format = DateTime)] pub start_date: DateTime, #[schema(value_type = String, format = DateTime)] pub end_date: DateTime, #[schema(value_type = String, format = DateTime)] pub registration_deadline: DateTime, #[validate(range(min = 1, max = 10000, message = "Max participants must be between 1 and 10000"))] pub max_participants: Option, pub theme: Option, pub rules: Option, pub prizes: Option>, pub organizers: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonUpdateRequestDto { #[validate(length(min = 1, max = 100, message = "Hackathon name must be between 1 and 100 characters"))] #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, #[validate(length(min = 1, max = 1000, message = "Description must be between 1 and 1000 characters"))] #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = String, format = DateTime)] pub start_date: Option>, #[schema(value_type = String, format = DateTime)] pub end_date: Option>, #[schema(value_type = String, format = DateTime)] pub registration_deadline: Option>, #[validate(range(min = 1, max = 10000, message = "Max participants must be between 1 and 10000"))] #[serde(skip_serializing_if = "Option::is_none")] pub max_participants: Option, #[serde(skip_serializing_if = "Option::is_none")] pub theme: Option, #[serde(skip_serializing_if = "Option::is_none")] pub rules: Option, #[serde(skip_serializing_if = "Option::is_none")] pub prizes: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub organizers: Option>, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct HackathonDto { pub id: String, pub name: String, pub description: String, #[schema(value_type = String, format = DateTime)] pub start_date: DateTime, #[schema(value_type = String, format = DateTime)] pub end_date: DateTime, #[schema(value_type = String, format = DateTime)] pub registration_deadline: DateTime, pub max_participants: Option, pub status: HackathonStatus, pub theme: Option, pub rules: Option, pub prizes: Option>, pub organizers: Vec, pub is_deleted: bool, pub created_at: Option, pub updated_at: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct PrizeDto { #[validate(range(min = 1, message = "Position must be at least 1"))] pub position: u32, #[validate(length(min = 1, message = "Prize title cannot be empty"))] pub title: String, pub description: Option, pub value: Option, } // Hackathon Events DTOs #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonEventCreateRequestDto { #[validate(length(min = 1, message = "Event title cannot be empty"))] pub title: String, pub description: Option, pub event_type: HackathonEventType, #[schema(value_type = String, format = DateTime)] pub start_time: DateTime, #[schema(value_type = String, format = DateTime)] pub end_time: DateTime, pub location: Option, pub virtual_link: Option, #[validate(range(min = 1, message = "Max attendees must be at least 1"))] pub max_attendees: Option, pub is_mandatory: bool, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonEventUpdateRequestDto { #[validate(length(min = 1, message = "Event title cannot be empty"))] #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] pub event_type: Option, #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = String, format = DateTime)] pub start_time: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = String, format = DateTime)] pub end_time: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub location: Option, #[serde(skip_serializing_if = "Option::is_none")] pub virtual_link: Option, #[validate(range(min = 1, message = "Max attendees must be at least 1"))] #[serde(skip_serializing_if = "Option::is_none")] pub max_attendees: Option, #[serde(skip_serializing_if = "Option::is_none")] pub is_mandatory: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct HackathonEventDto { pub id: String, pub hackathon_id: String, pub title: String, pub description: Option, pub event_type: HackathonEventType, #[schema(value_type = String, format = DateTime)] pub start_time: DateTime, #[schema(value_type = String, format = DateTime)] pub end_time: DateTime, pub location: Option, pub virtual_link: Option, pub max_attendees: Option, pub is_mandatory: bool, pub is_deleted: bool, pub created_at: Option, pub updated_at: Option, } // Hackathon Timeline DTOs #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonTimelineCreateRequestDto { pub phase: HackathonPhase, #[validate(length(min = 1, message = "Timeline title cannot be empty"))] pub title: String, pub description: Option, #[schema(value_type = String, format = DateTime)] pub start_date: DateTime, #[schema(value_type = String, format = DateTime)] pub end_date: DateTime, pub is_active: bool, #[validate(range(min = 0, message = "Order must be non-negative"))] pub order: u32, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonTimelineUpdateRequestDto { #[serde(skip_serializing_if = "Option::is_none")] pub phase: Option, #[validate(length(min = 1, message = "Timeline title cannot be empty"))] #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = String, format = DateTime)] pub start_date: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = String, format = DateTime)] pub end_date: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub is_active: Option, #[validate(range(min = 0, message = "Order must be non-negative"))] #[serde(skip_serializing_if = "Option::is_none")] pub order: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct HackathonTimelineDto { pub id: String, pub hackathon_id: String, pub phase: HackathonPhase, pub title: String, pub description: Option, #[schema(value_type = String, format = DateTime)] pub start_date: DateTime, #[schema(value_type = String, format = DateTime)] pub end_date: DateTime, pub is_active: bool, pub order: u32, pub is_deleted: bool, pub created_at: Option, pub updated_at: Option, } // Hackathon Submissions DTOs #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonSubmissionCreateRequestDto { #[validate(length(min = 1, message = "Project name cannot be empty"))] pub project_name: String, #[validate(length(min = 1, message = "Description cannot be empty"))] pub description: String, pub repository_url: Option, pub demo_url: Option, pub slides_url: Option, pub technologies: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonSubmissionUpdateRequestDto { #[validate(length(min = 1, message = "Project name cannot be empty"))] #[serde(skip_serializing_if = "Option::is_none")] pub project_name: Option, #[validate(length(min = 1, message = "Description cannot be empty"))] #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, #[serde(skip_serializing_if = "Option::is_none")] pub repository_url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub demo_url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub slides_url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub technologies: Option>, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct HackathonSubmissionDto { pub id: String, pub hackathon_id: String, pub team_id: String, pub project_name: String, pub description: String, pub repository_url: Option, pub demo_url: Option, pub slides_url: Option, pub technologies: Vec, pub submission_status: SubmissionStatus, #[schema(value_type = String, format = DateTime)] pub submitted_at: DateTime, pub is_deleted: bool, pub created_at: Option, pub updated_at: Option, } // Query DTOs #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonQueryDto { #[serde(skip_serializing_if = "Option::is_none")] pub status: Option, #[serde(skip_serializing_if = "Option::is_none")] pub organizer_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, #[serde(skip_serializing_if = "Option::is_none")] pub offset: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonEventQueryDto { pub hackathon_id: String, #[serde(skip_serializing_if = "Option::is_none")] pub event_type: Option, #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, #[serde(skip_serializing_if = "Option::is_none")] pub offset: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonTimelineQueryDto { pub hackathon_id: String, #[serde(skip_serializing_if = "Option::is_none")] pub phase: Option, #[serde(skip_serializing_if = "Option::is_none")] pub is_active: Option, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] pub struct HackathonSubmissionQueryDto { pub hackathon_id: String, #[serde(skip_serializing_if = "Option::is_none")] pub team_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub submission_status: Option, #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, #[serde(skip_serializing_if = "Option::is_none")] pub offset: Option, } // Conversion implementations impl From for HackathonDto { fn from(schema: HackathonSchema) -> Self { Self { id: schema.id.id.to_raw(), name: schema.name, description: schema.description, start_date: schema.start_date, end_date: schema.end_date, registration_deadline: schema.registration_deadline, max_participants: schema.max_participants, status: schema.status, theme: schema.theme, rules: schema.rules, prizes: schema.prizes.map(|prizes| { prizes .into_iter() .map(|p| PrizeDto { position: p.position, title: p.title, description: p.description, value: p.value, }) .collect() }), organizers: schema.organizers, is_deleted: schema.is_deleted, created_at: schema.created_at, updated_at: schema.updated_at, } } } impl From for HackathonEventDto { fn from(schema: HackathonEventsSchema) -> Self { Self { id: schema.id.id.to_raw(), hackathon_id: schema.hackathon_id.id.to_raw(), title: schema.title, description: schema.description, event_type: schema.event_type, start_time: schema.start_time, end_time: schema.end_time, location: schema.location, virtual_link: schema.virtual_link, max_attendees: schema.max_attendees, is_mandatory: schema.is_mandatory, is_deleted: schema.is_deleted, created_at: schema.created_at, updated_at: schema.updated_at, } } } impl From for HackathonTimelineDto { fn from(schema: HackathonTimelineSchema) -> Self { Self { id: schema.id.id.to_raw(), hackathon_id: schema.hackathon_id.id.to_raw(), phase: schema.phase, title: schema.title, description: schema.description, start_date: schema.start_date, end_date: schema.end_date, is_active: schema.is_active, order: schema.order, is_deleted: schema.is_deleted, created_at: schema.created_at, updated_at: schema.updated_at, } } } impl From for HackathonSubmissionDto { fn from(schema: HackathonSubmissionsSchema) -> Self { Self { id: schema.id.id.to_raw(), hackathon_id: schema.hackathon_id.id.to_raw(), team_id: schema.team_id.id.to_raw(), project_name: schema.project_name, description: schema.description, repository_url: schema.repository_url, demo_url: schema.demo_url, slides_url: schema.slides_url, technologies: schema.technologies, submission_status: schema.submission_status, submitted_at: schema.submitted_at, is_deleted: schema.is_deleted, created_at: schema.created_at, updated_at: schema.updated_at, } } }