use crate::application::dtos::calendar_dto::{ CalendarDto, CalendarEventDto, CreateCalendarDto, CreateEventDto, CreateEventICalDto, UpdateCalendarDto, UpdateEventDto, }; use crate::common::errors::DomainError; use chrono::{DateTime, Utc}; use uuid::Uuid; /// Port for external calendar storage mechanisms pub trait CalendarStoragePort: Send + Sync + 'static { // Calendar operations async fn create_calendar( &self, calendar: CreateCalendarDto, owner_id: Uuid, ) -> Result; async fn update_calendar( &self, calendar_id: &str, update: UpdateCalendarDto, ) -> Result; async fn delete_calendar(&self, calendar_id: &str) -> Result<(), DomainError>; async fn get_calendar(&self, calendar_id: &str) -> Result; async fn list_calendars_by_owner( &self, owner_id: Uuid, ) -> Result, DomainError>; async fn list_calendars_shared_with_user( &self, user_id: Uuid, ) -> Result, DomainError>; async fn list_public_calendars( &self, limit: i64, offset: i64, ) -> Result, DomainError>; async fn check_calendar_access( &self, calendar_id: &str, user_id: Uuid, ) -> Result; // Calendar sharing async fn share_calendar( &self, calendar_id: &str, user_id: Uuid, access_level: &str, ) -> Result<(), DomainError>; async fn remove_calendar_sharing( &self, calendar_id: &str, user_id: Uuid, ) -> Result<(), DomainError>; async fn get_calendar_shares( &self, calendar_id: &str, ) -> Result, DomainError>; // Calendar properties async fn set_calendar_property( &self, calendar_id: &str, property_name: &str, property_value: &str, ) -> Result<(), DomainError>; async fn get_calendar_property( &self, calendar_id: &str, property_name: &str, ) -> Result, DomainError>; async fn get_calendar_properties( &self, calendar_id: &str, ) -> Result, DomainError>; // Event operations async fn create_event(&self, event: CreateEventDto) -> Result; async fn create_event_from_ical( &self, event: CreateEventICalDto, ) -> Result; async fn update_event( &self, event_id: &str, update: UpdateEventDto, ) -> Result; async fn delete_event(&self, event_id: &str) -> Result<(), DomainError>; async fn get_event(&self, event_id: &str) -> Result; /// Indexed single-row lookup by iCalendar UID — the CalDAV /// object-resource paths must use this instead of listing the whole /// calendar (every row + its `ical_data`) and filtering client-side. async fn find_event_by_ical_uid( &self, calendar_id: &str, ical_uid: &str, ) -> Result, DomainError>; /// Indexed batch lookup by iCalendar UID (`ical_uid = ANY(...)`) — the /// CalDAV multiget REPORT must use this instead of listing the whole /// calendar (every row + its `ical_data`) and filtering client-side. async fn find_events_by_ical_uids( &self, calendar_id: &str, ical_uids: &[String], ) -> Result, DomainError>; async fn list_events_by_calendar( &self, calendar_id: &str, ) -> Result, DomainError>; async fn list_events_by_calendar_paginated( &self, calendar_id: &str, limit: i64, offset: i64, ) -> Result, DomainError>; async fn get_events_in_time_range( &self, calendar_id: &str, start: &DateTime, end: &DateTime, ) -> Result, DomainError>; } /// Port for calendar use cases. /// /// All methods require an explicit `user_id` parameter for authorization. /// The CalDAV protocol handler extracts the user identity from JWT claims /// and passes it through. pub trait CalendarUseCase: Send + Sync + 'static { // Calendar operations async fn create_calendar( &self, calendar: CreateCalendarDto, user_id: Uuid, ) -> Result; async fn update_calendar( &self, calendar_id: &str, update: UpdateCalendarDto, user_id: Uuid, ) -> Result; async fn delete_calendar(&self, calendar_id: &str, user_id: Uuid) -> Result<(), DomainError>; async fn get_calendar( &self, calendar_id: &str, user_id: Uuid, ) -> Result; async fn list_my_calendars(&self, user_id: Uuid) -> Result, DomainError>; async fn list_shared_calendars(&self, user_id: Uuid) -> Result, DomainError>; async fn list_public_calendars( &self, limit: Option, offset: Option, ) -> Result, DomainError>; // Calendar sharing async fn share_calendar( &self, calendar_id: &str, target_user_id: Uuid, access_level: &str, caller_user_id: Uuid, ) -> Result<(), DomainError>; async fn remove_calendar_sharing( &self, calendar_id: &str, target_user_id: Uuid, caller_user_id: Uuid, ) -> Result<(), DomainError>; async fn get_calendar_shares( &self, calendar_id: &str, user_id: Uuid, ) -> Result, DomainError>; // Event operations async fn create_event( &self, event: CreateEventDto, user_id: Uuid, ) -> Result; async fn create_event_from_ical( &self, event: CreateEventICalDto, user_id: Uuid, ) -> Result; async fn update_event( &self, event_id: &str, update: UpdateEventDto, user_id: Uuid, ) -> Result; async fn delete_event(&self, event_id: &str, user_id: Uuid) -> Result<(), DomainError>; async fn get_event( &self, event_id: &str, user_id: Uuid, ) -> Result; /// Resolve one event by its iCalendar UID (the identifier CalDAV /// object resources are addressed by). `Ok(None)` when no event with /// that UID exists in the calendar. async fn get_event_by_ical_uid( &self, calendar_id: &str, ical_uid: &str, user_id: Uuid, ) -> Result, DomainError>; /// Resolve a batch of events by their iCalendar UIDs with a single /// indexed query. UIDs without a matching event are silently absent /// from the result (CalDAV multiget semantics). async fn get_events_by_ical_uids( &self, calendar_id: &str, ical_uids: &[String], user_id: Uuid, ) -> Result, DomainError>; async fn list_events( &self, calendar_id: &str, limit: Option, offset: Option, user_id: Uuid, ) -> Result, DomainError>; async fn get_events_in_range( &self, calendar_id: &str, start: DateTime, end: DateTime, user_id: Uuid, ) -> Result, DomainError>; }