use chrono::{DateTime, Utc};
use uuid::Uuid;
use super::capability::{mint_ticket_report_capability, CapabilityClaims, PURPOSE_TICKET_REPORT};
use super::event_error::{EventError, EventResult};
use crate::infrastructure::persistence::event_command_repository::EventCommandRepository;
use crate::infrastructure::persistence::seat_repository::{RegistrationRow, SeatRepository};
#[derive(Debug, Clone, serde::Serialize)]
pub struct TicketView {
pub registration_id: Uuid,
pub event_id: Uuid,
pub event_name: String,
pub event_date_begin: DateTime<Utc>,
pub event_date_end: DateTime<Utc>,
pub event_date_tz: String,
pub attendee_name: String,
pub state: String,
pub barcode: String,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct TicketReport {
pub event_id: Uuid,
pub event_name: String,
pub event_date_begin: DateTime<Utc>,
pub event_date_end: DateTime<Utc>,
pub event_date_tz: String,
pub badge_format: String,
pub tickets: Vec<TicketView>,
}
pub struct MyTicketsService {
events: EventCommandRepository,
seats: SeatRepository,
}
impl MyTicketsService {
pub fn new(events: EventCommandRepository, seats: SeatRepository) -> Self {
Self { events, seats }
}
pub fn mint(
&self,
secret: &str,
event_id: Uuid,
registration_ids: &[Uuid],
) -> EventResult<String> {
mint_ticket_report_capability(secret, &event_id, registration_ids)
}
pub async fn report(&self, secret: &str, token: &str) -> EventResult<TicketReport> {
let claims = CapabilityClaims::verify(secret, PURPOSE_TICKET_REPORT, token, Utc::now())?;
let event_id = claims
.data
.first()
.and_then(|s| Uuid::parse_str(s).ok())
.ok_or(EventError::EventNotPublished)?;
let pinned: Vec<Uuid> = claims
.data
.iter()
.skip(1)
.filter_map(|s| Uuid::parse_str(s).ok())
.collect();
let event = self.events.find_published(event_id).await?;
let mut tickets = Vec::with_capacity(pinned.len());
for reg_id in pinned {
if let Ok(row) = self.seats.find_registration(reg_id).await {
if row.event_id == event_id {
tickets.push(ticket_of(&event, &row));
}
}
}
Ok(TicketReport {
event_id: event.id,
event_name: event.name.clone(),
event_date_begin: event.date_begin,
event_date_end: event.date_end,
event_date_tz: event.date_tz.clone(),
badge_format: event.badge_format.clone(),
tickets,
})
}
}
fn ticket_of(
event: &crate::infrastructure::persistence::event_command_repository::EventRow,
row: &RegistrationRow,
) -> TicketView {
TicketView {
registration_id: row.id,
event_id: event.id,
event_name: event.name.clone(),
event_date_begin: event.date_begin,
event_date_end: event.date_end,
event_date_tz: event.date_tz.clone(),
attendee_name: row.name.clone(),
state: row.state.clone(),
barcode: row.barcode.clone(),
}
}