2025-11-22 22:55:35 -03:00
|
|
|
use axum::{
|
2025-11-27 23:10:43 -03:00
|
|
|
extract::{Path, State},
|
2025-11-22 22:55:35 -03:00
|
|
|
http::StatusCode,
|
|
|
|
|
response::Json,
|
2025-11-27 23:10:43 -03:00
|
|
|
routing::{get, post},
|
2025-11-22 22:55:35 -03:00
|
|
|
Router,
|
|
|
|
|
};
|
|
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::sync::Arc;
|
2025-11-28 09:27:29 -03:00
|
|
|
use uuid::Uuid;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
2025-11-29 16:29:28 -03:00
|
|
|
use crate::core::urls::ApiUrls;
|
2025-11-27 23:10:43 -03:00
|
|
|
use crate::shared::state::AppState;
|
2025-11-22 22:55:35 -03:00
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-11-22 22:55:35 -03:00
|
|
|
pub struct CalendarEvent {
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
pub title: String,
|
|
|
|
|
pub description: Option<String>,
|
|
|
|
|
pub start_time: DateTime<Utc>,
|
|
|
|
|
pub end_time: DateTime<Utc>,
|
|
|
|
|
pub location: Option<String>,
|
|
|
|
|
pub attendees: Vec<String>,
|
|
|
|
|
pub organizer: String,
|
|
|
|
|
pub reminder_minutes: Option<i32>,
|
2025-11-28 09:27:29 -03:00
|
|
|
pub recurrence: Option<String>,
|
2025-11-22 22:55:35 -03:00
|
|
|
pub created_at: DateTime<Utc>,
|
|
|
|
|
pub updated_at: DateTime<Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-11-28 09:27:29 -03:00
|
|
|
pub struct CalendarEventInput {
|
2025-11-27 09:38:50 -03:00
|
|
|
pub title: String,
|
|
|
|
|
pub description: Option<String>,
|
|
|
|
|
pub start_time: DateTime<Utc>,
|
|
|
|
|
pub end_time: DateTime<Utc>,
|
|
|
|
|
pub location: Option<String>,
|
2025-11-28 09:27:29 -03:00
|
|
|
pub attendees: Vec<String>,
|
2025-11-27 09:38:50 -03:00
|
|
|
pub organizer: String,
|
|
|
|
|
pub reminder_minutes: Option<i32>,
|
2025-11-28 09:27:29 -03:00
|
|
|
pub recurrence: Option<String>,
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-11-28 09:27:29 -03:00
|
|
|
pub struct CalendarReminder {
|
|
|
|
|
pub id: Uuid,
|
|
|
|
|
pub event_id: Uuid,
|
|
|
|
|
pub reminder_type: String,
|
|
|
|
|
pub trigger_time: DateTime<Utc>,
|
|
|
|
|
pub channel: String,
|
|
|
|
|
pub sent: bool,
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-11-28 09:27:29 -03:00
|
|
|
pub struct MeetingSummary {
|
|
|
|
|
pub event_id: Uuid,
|
2025-11-27 09:38:50 -03:00
|
|
|
pub title: String,
|
2025-11-28 09:27:29 -03:00
|
|
|
pub summary: String,
|
|
|
|
|
pub action_items: Vec<String>,
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-11-28 09:27:29 -03:00
|
|
|
pub struct RecurrenceRule {
|
|
|
|
|
pub frequency: String,
|
|
|
|
|
pub interval: Option<i32>,
|
|
|
|
|
pub count: Option<i32>,
|
|
|
|
|
pub until: Option<DateTime<Utc>>,
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-22 22:55:35 -03:00
|
|
|
pub struct CalendarEngine {
|
2025-11-28 09:27:29 -03:00
|
|
|
events: Vec<CalendarEvent>,
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CalendarEngine {
|
2025-11-28 09:27:29 -03:00
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self { events: Vec::new() }
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
pub async fn create_event(
|
2025-11-28 09:27:29 -03:00
|
|
|
&mut self,
|
|
|
|
|
event: CalendarEventInput,
|
|
|
|
|
) -> Result<CalendarEvent, String> {
|
2025-11-27 09:38:50 -03:00
|
|
|
let calendar_event = CalendarEvent {
|
2025-11-28 09:27:29 -03:00
|
|
|
id: Uuid::new_v4(),
|
2025-11-27 09:38:50 -03:00
|
|
|
title: event.title,
|
|
|
|
|
description: event.description,
|
|
|
|
|
start_time: event.start_time,
|
|
|
|
|
end_time: event.end_time,
|
|
|
|
|
location: event.location,
|
2025-11-28 09:27:29 -03:00
|
|
|
attendees: event.attendees,
|
2025-11-27 09:38:50 -03:00
|
|
|
organizer: event.organizer,
|
|
|
|
|
reminder_minutes: event.reminder_minutes,
|
2025-11-28 09:27:29 -03:00
|
|
|
recurrence: event.recurrence,
|
|
|
|
|
created_at: Utc::now(),
|
|
|
|
|
updated_at: Utc::now(),
|
2025-11-27 09:38:50 -03:00
|
|
|
};
|
2025-11-28 09:27:29 -03:00
|
|
|
self.events.push(calendar_event.clone());
|
2025-11-27 09:38:50 -03:00
|
|
|
Ok(calendar_event)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn get_event(&self, id: Uuid) -> Result<Option<CalendarEvent>, String> {
|
|
|
|
|
Ok(self.events.iter().find(|e| e.id == id).cloned())
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
pub async fn update_event(
|
2025-11-28 09:27:29 -03:00
|
|
|
&mut self,
|
2025-11-27 23:10:43 -03:00
|
|
|
id: Uuid,
|
2025-11-28 09:27:29 -03:00
|
|
|
updates: CalendarEventInput,
|
|
|
|
|
) -> Result<CalendarEvent, String> {
|
|
|
|
|
if let Some(event) = self.events.iter_mut().find(|e| e.id == id) {
|
|
|
|
|
event.title = updates.title;
|
|
|
|
|
event.description = updates.description;
|
|
|
|
|
event.start_time = updates.start_time;
|
|
|
|
|
event.end_time = updates.end_time;
|
|
|
|
|
event.location = updates.location;
|
|
|
|
|
event.attendees = updates.attendees;
|
|
|
|
|
event.organizer = updates.organizer;
|
|
|
|
|
event.reminder_minutes = updates.reminder_minutes;
|
|
|
|
|
event.recurrence = updates.recurrence;
|
2025-11-27 09:38:50 -03:00
|
|
|
event.updated_at = Utc::now();
|
|
|
|
|
Ok(event.clone())
|
|
|
|
|
} else {
|
2025-11-28 09:27:29 -03:00
|
|
|
Err("Event not found".to_string())
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn delete_event(&mut self, id: Uuid) -> Result<bool, String> {
|
|
|
|
|
let initial_len = self.events.len();
|
|
|
|
|
self.events.retain(|e| e.id != id);
|
|
|
|
|
Ok(self.events.len() < initial_len)
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-27 23:10:43 -03:00
|
|
|
pub async fn list_events(
|
|
|
|
|
&self,
|
2025-11-28 09:27:29 -03:00
|
|
|
limit: Option<i64>,
|
|
|
|
|
offset: Option<i64>,
|
|
|
|
|
) -> Result<Vec<CalendarEvent>, String> {
|
|
|
|
|
let limit = limit.unwrap_or(50) as usize;
|
|
|
|
|
let offset = offset.unwrap_or(0) as usize;
|
|
|
|
|
Ok(self
|
|
|
|
|
.events
|
2025-11-27 09:38:50 -03:00
|
|
|
.iter()
|
2025-11-28 09:27:29 -03:00
|
|
|
.skip(offset)
|
|
|
|
|
.take(limit)
|
2025-11-27 09:38:50 -03:00
|
|
|
.cloned()
|
2025-11-28 09:27:29 -03:00
|
|
|
.collect())
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn get_events_range(
|
2025-11-27 23:10:43 -03:00
|
|
|
&self,
|
2025-11-28 09:27:29 -03:00
|
|
|
start: DateTime<Utc>,
|
|
|
|
|
end: DateTime<Utc>,
|
|
|
|
|
) -> Result<Vec<CalendarEvent>, String> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|e| e.start_time >= start && e.end_time <= end)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect())
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn get_user_events(&self, user_id: &str) -> Result<Vec<CalendarEvent>, String> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|e| e.organizer == user_id)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect())
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn create_reminder(
|
2025-11-27 23:10:43 -03:00
|
|
|
&self,
|
2025-11-28 09:27:29 -03:00
|
|
|
event_id: Uuid,
|
|
|
|
|
reminder_type: String,
|
|
|
|
|
trigger_time: DateTime<Utc>,
|
|
|
|
|
channel: String,
|
|
|
|
|
) -> Result<CalendarReminder, String> {
|
|
|
|
|
Ok(CalendarReminder {
|
2025-11-27 09:38:50 -03:00
|
|
|
id: Uuid::new_v4(),
|
2025-11-28 09:27:29 -03:00
|
|
|
event_id,
|
|
|
|
|
reminder_type,
|
|
|
|
|
trigger_time,
|
|
|
|
|
channel,
|
2025-11-27 09:38:50 -03:00
|
|
|
sent: false,
|
2025-11-28 09:27:29 -03:00
|
|
|
})
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn check_conflicts(
|
|
|
|
|
&self,
|
|
|
|
|
start: DateTime<Utc>,
|
|
|
|
|
end: DateTime<Utc>,
|
|
|
|
|
user_id: &str,
|
|
|
|
|
) -> Result<Vec<CalendarEvent>, String> {
|
|
|
|
|
Ok(self
|
|
|
|
|
.events
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|e| {
|
|
|
|
|
e.organizer == user_id
|
|
|
|
|
&& ((e.start_time < end && e.end_time > start)
|
|
|
|
|
|| (e.start_time >= start && e.start_time < end))
|
|
|
|
|
})
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect())
|
2025-11-27 09:38:50 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn list_events(
|
|
|
|
|
State(_state): State<Arc<AppState>>,
|
|
|
|
|
axum::extract::Query(_query): axum::extract::Query<serde_json::Value>,
|
2025-11-27 09:38:50 -03:00
|
|
|
) -> Result<Json<Vec<CalendarEvent>>, StatusCode> {
|
2025-11-28 09:27:29 -03:00
|
|
|
Ok(Json(vec![]))
|
2025-11-26 22:54:22 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn get_event(
|
|
|
|
|
State(_state): State<Arc<AppState>>,
|
|
|
|
|
Path(_id): Path<Uuid>,
|
|
|
|
|
) -> Result<Json<Option<CalendarEvent>>, StatusCode> {
|
|
|
|
|
Ok(Json(None))
|
2025-11-26 22:54:22 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn create_event(
|
|
|
|
|
State(_state): State<Arc<AppState>>,
|
|
|
|
|
Json(_event): Json<CalendarEventInput>,
|
2025-11-22 22:55:35 -03:00
|
|
|
) -> Result<Json<CalendarEvent>, StatusCode> {
|
2025-11-28 09:27:29 -03:00
|
|
|
Err(StatusCode::NOT_IMPLEMENTED)
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn update_event(
|
|
|
|
|
State(_state): State<Arc<AppState>>,
|
|
|
|
|
Path(_id): Path<Uuid>,
|
|
|
|
|
Json(_updates): Json<CalendarEventInput>,
|
2025-11-22 22:55:35 -03:00
|
|
|
) -> Result<Json<CalendarEvent>, StatusCode> {
|
2025-11-28 09:27:29 -03:00
|
|
|
Err(StatusCode::NOT_IMPLEMENTED)
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub async fn delete_event(
|
|
|
|
|
State(_state): State<Arc<AppState>>,
|
|
|
|
|
Path(_id): Path<Uuid>,
|
2025-11-22 22:55:35 -03:00
|
|
|
) -> Result<StatusCode, StatusCode> {
|
2025-11-28 09:27:29 -03:00
|
|
|
Err(StatusCode::NOT_IMPLEMENTED)
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 09:27:29 -03:00
|
|
|
pub fn router(state: Arc<AppState>) -> Router {
|
2025-11-22 22:55:35 -03:00
|
|
|
Router::new()
|
|
|
|
|
.route(
|
2025-11-29 16:29:28 -03:00
|
|
|
ApiUrls::CALENDAR_EVENTS,
|
|
|
|
|
get(list_events).post(create_event),
|
|
|
|
|
)
|
|
|
|
|
.route(
|
|
|
|
|
ApiUrls::CALENDAR_EVENT_BY_ID.replace(":id", "{id}"),
|
2025-11-28 09:27:29 -03:00
|
|
|
get(get_event).put(update_event).delete(delete_event),
|
2025-11-22 22:55:35 -03:00
|
|
|
)
|
2025-11-28 09:27:29 -03:00
|
|
|
.with_state(state)
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|