//! Event DTOs (Data Transfer Objects)
//!
//! Generated by metaphor-schema. Do not edit manually.
//!
//! DTOs provide a clean separation between domain entities and API
//! representations, with validation and OpenAPI documentation support.
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[cfg(feature = "openapi")]
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[cfg(feature = "validation")]
use validator::Validate;
use crate::domain::entity::Event;
use crate::domain::entity::AuditMetadata;
use crate::domain::entity::EventBadgeFormat;
use crate::domain::entity::EventKanbanState;
// =============================================================================
// Create DTO
// =============================================================================
/// Request DTO for creating a new Event
///
/// Used in POST requests to create new entities.
/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct CreateEventDto {
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_type_id")]
pub event_type_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "stage_id")]
pub stage_id: Uuid,
#[serde(alias = "kanban_state")]
pub kanban_state: EventKanbanState,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(alias = "date_begin")]
pub date_begin: DateTime<Utc>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(alias = "date_end")]
pub date_end: DateTime<Utc>,
#[cfg_attr(feature = "validation", validate(length(max = 60)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(alias = "date_tz")]
pub date_tz: String,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_multi_slots")]
pub is_multi_slots: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "event_slot_count")]
pub event_slot_count: i32,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "seats_limited")]
pub seats_limited: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "seats_max")]
pub seats_max: i32,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "address_id")]
pub address_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "organizer_id")]
pub organizer_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(url))]
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_url")]
pub event_url: Option<String>,
#[serde(alias = "badge_format")]
pub badge_format: EventBadgeFormat,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_published")]
pub is_published: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "date_publish")]
pub date_publish: Option<DateTime<Utc>>,
}
// =============================================================================
// Update DTO
// =============================================================================
/// Request DTO for full update of a Event
///
/// Used in PUT requests for full entity replacement.
/// All fields are required (except auto-generated ones).
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct UpdateEventDto {
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_type_id")]
pub event_type_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "stage_id")]
pub stage_id: Uuid,
#[serde(alias = "kanban_state")]
pub kanban_state: EventKanbanState,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(alias = "date_begin")]
pub date_begin: DateTime<Utc>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(alias = "date_end")]
pub date_end: DateTime<Utc>,
#[cfg_attr(feature = "validation", validate(length(max = 60)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(alias = "date_tz")]
pub date_tz: String,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_multi_slots")]
pub is_multi_slots: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "event_slot_count")]
pub event_slot_count: i32,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "seats_limited")]
pub seats_limited: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "seats_max")]
pub seats_max: i32,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "address_id")]
pub address_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "organizer_id")]
pub organizer_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(url))]
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_url")]
pub event_url: Option<String>,
#[serde(alias = "badge_format")]
pub badge_format: EventBadgeFormat,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_published")]
pub is_published: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "date_publish")]
pub date_publish: Option<DateTime<Utc>>,
}
// =============================================================================
// Patch DTO
// =============================================================================
/// Request DTO for partial update of a Event
///
/// Used in PATCH requests for partial updates.
/// All fields are optional - only provided fields will be updated.
#[derive(Debug, Clone, Default, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct PatchEventDto {
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "event_type_id")]
pub event_type_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "stage_id")]
pub stage_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "kanban_state")]
pub kanban_state: Option<EventKanbanState>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "date_begin")]
pub date_begin: Option<DateTime<Utc>>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "date_end")]
pub date_end: Option<DateTime<Utc>>,
#[cfg_attr(feature = "validation", validate(length(max = 60)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "date_tz")]
pub date_tz: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "is_multi_slots")]
pub is_multi_slots: Option<bool>,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(skip_serializing_if = "Option::is_none", alias = "event_slot_count")]
pub event_slot_count: Option<i32>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "seats_limited")]
pub seats_limited: Option<bool>,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(skip_serializing_if = "Option::is_none", alias = "seats_max")]
pub seats_max: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none", alias = "address_id")]
pub address_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "organizer_id")]
pub organizer_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(url))]
#[serde(skip_serializing_if = "Option::is_none", alias = "event_url")]
pub event_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "badge_format")]
pub badge_format: Option<EventBadgeFormat>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "is_published")]
pub is_published: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", alias = "date_publish")]
pub date_publish: Option<DateTime<Utc>>,
}
impl PatchEventDto {
/// Check if any field is set
pub fn has_changes(&self) -> bool {
self.name.is_some() || self.event_type_id.is_some() || self.stage_id.is_some() || self.kanban_state.is_some() || self.date_begin.is_some() || self.date_end.is_some() || self.date_tz.is_some() || self.is_multi_slots.is_some() || self.event_slot_count.is_some() || self.seats_limited.is_some() || self.seats_max.is_some() || self.address_id.is_some() || self.organizer_id.is_some() || self.user_id.is_some() || self.event_url.is_some() || self.badge_format.is_some() || self.is_published.is_some() || self.date_publish.is_some()
}
}
// =============================================================================
// Response DTO
// =============================================================================
/// Response DTO for Event entity
///
/// Used in API responses for single entity.
/// Includes all fields including metadata.
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct EventResponseDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub id: Uuid,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
pub event_type_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub stage_id: Uuid,
pub kanban_state: EventKanbanState,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
pub date_begin: DateTime<Utc>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
pub date_end: DateTime<Utc>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub date_tz: String,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub is_multi_slots: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
pub event_slot_count: i32,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub seats_limited: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
pub seats_max: i32,
pub address_id: Option<Uuid>,
pub organizer_id: Option<Uuid>,
pub user_id: Option<Uuid>,
pub event_url: Option<String>,
pub badge_format: EventBadgeFormat,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub is_published: bool,
pub date_publish: Option<DateTime<Utc>>,
pub metadata: AuditMetadata,
}
// =============================================================================
// List Response DTO
// =============================================================================
/// Paginated list response for Event entities
///
/// Used in API responses for list endpoints.
/// Includes pagination metadata.
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct EventListResponseDto {
/// List of items
pub items: Vec<EventResponseDto>,
/// Total number of items (across all pages)
pub total: u64,
/// Current page number (1-indexed)
pub page: u32,
/// Number of items per page
pub per_page: u32,
/// Total number of pages
pub total_pages: u32,
/// Whether there is a next page
pub has_next: bool,
/// Whether there is a previous page
pub has_prev: bool,
}
impl EventListResponseDto {
/// Create a new list response from items and pagination info
pub fn new(items: Vec<EventResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
let total_pages = if per_page > 0 {
((total as f64) / (per_page as f64)).ceil() as u32
} else {
0
};
Self {
items,
total,
page,
per_page,
total_pages,
has_next: page < total_pages,
has_prev: page > 1,
}
}
}
/// Summary DTO for list views (compact version)
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct EventSummaryDto {
pub id: Uuid,
pub name: String,
pub event_type_id: Option<Uuid>,
pub stage_id: Uuid,
pub created_at: Option<DateTime<Utc>>,
}
// =============================================================================
// Conversions
// =============================================================================
impl From<Event> for EventResponseDto {
fn from(entity: Event) -> Self {
Self {
id: entity.id,
name: entity.name,
event_type_id: entity.event_type_id,
stage_id: entity.stage_id,
kanban_state: entity.kanban_state,
date_begin: entity.date_begin,
date_end: entity.date_end,
date_tz: entity.date_tz,
is_multi_slots: entity.is_multi_slots,
event_slot_count: entity.event_slot_count,
seats_limited: entity.seats_limited,
seats_max: entity.seats_max,
address_id: entity.address_id,
organizer_id: entity.organizer_id,
user_id: entity.user_id,
event_url: entity.event_url,
badge_format: entity.badge_format,
is_published: entity.is_published,
date_publish: entity.date_publish,
metadata: entity.metadata,
}
}
}
impl From<Event> for EventSummaryDto {
fn from(entity: Event) -> Self {
let created_at = backbone_core::PersistentEntity::created_at(&entity);
Self {
id: entity.id,
name: entity.name,
event_type_id: entity.event_type_id,
stage_id: entity.stage_id,
created_at,
}
}
}
impl From<CreateEventDto> for Event {
fn from(dto: CreateEventDto) -> Self {
Self {
id: Uuid::new_v4(),
name: dto.name,
event_type_id: dto.event_type_id,
stage_id: dto.stage_id,
kanban_state: dto.kanban_state,
date_begin: dto.date_begin,
date_end: dto.date_end,
date_tz: dto.date_tz,
is_multi_slots: dto.is_multi_slots,
event_slot_count: dto.event_slot_count,
seats_limited: dto.seats_limited,
seats_max: dto.seats_max,
address_id: dto.address_id,
organizer_id: dto.organizer_id,
user_id: dto.user_id,
event_url: dto.event_url,
badge_format: dto.badge_format,
is_published: dto.is_published,
date_publish: dto.date_publish,
metadata: AuditMetadata::default(),
}
}
}
impl From<&Event> for EventResponseDto {
fn from(entity: &Event) -> Self {
Self {
id: entity.id.clone(),
name: entity.name.clone(),
event_type_id: entity.event_type_id.clone(),
stage_id: entity.stage_id.clone(),
kanban_state: entity.kanban_state.clone(),
date_begin: entity.date_begin.clone(),
date_end: entity.date_end.clone(),
date_tz: entity.date_tz.clone(),
is_multi_slots: entity.is_multi_slots.clone(),
event_slot_count: entity.event_slot_count.clone(),
seats_limited: entity.seats_limited.clone(),
seats_max: entity.seats_max.clone(),
address_id: entity.address_id.clone(),
organizer_id: entity.organizer_id.clone(),
user_id: entity.user_id.clone(),
event_url: entity.event_url.clone(),
badge_format: entity.badge_format.clone(),
is_published: entity.is_published.clone(),
date_publish: entity.date_publish.clone(),
metadata: entity.metadata.clone(),
}
}
}
impl backbone_core::FromCreateDto<CreateEventDto> for Event {
fn from_create_dto(dto: CreateEventDto) -> backbone_core::ServiceResult<Self> {
Ok(Event::from(dto))
}
}
impl backbone_core::ApplyUpdateDto<UpdateEventDto> for Event {
fn apply_update(mut self, dto: UpdateEventDto) -> backbone_core::ServiceResult<Self> {
self.name = dto.name;
self.event_type_id = dto.event_type_id;
self.stage_id = dto.stage_id;
self.kanban_state = dto.kanban_state;
self.date_begin = dto.date_begin;
self.date_end = dto.date_end;
self.date_tz = dto.date_tz;
self.is_multi_slots = dto.is_multi_slots;
self.event_slot_count = dto.event_slot_count;
self.seats_limited = dto.seats_limited;
self.seats_max = dto.seats_max;
self.address_id = dto.address_id;
self.organizer_id = dto.organizer_id;
self.user_id = dto.user_id;
self.event_url = dto.event_url;
self.badge_format = dto.badge_format;
self.is_published = dto.is_published;
self.date_publish = dto.date_publish;
Ok(self)
}
}
// =============================================================================
// Custom DTOs
// =============================================================================
// Add custom DTOs specific to Event here.
// This section will be preserved during regeneration.
// >>> END CUSTOM DTOs