diff --git a/actix_mvc_app/src/controllers/calendar.rs b/actix_mvc_app/src/controllers/calendar.rs index e4bfbc6..ee99d9e 100644 --- a/actix_mvc_app/src/controllers/calendar.rs +++ b/actix_mvc_app/src/controllers/calendar.rs @@ -1,12 +1,16 @@ -use actix_web::{web, HttpResponse, Responder, Result}; use actix_session::Session; +use actix_web::{HttpResponse, Responder, Result, web}; use chrono::{DateTime, Datelike, NaiveDate, TimeZone, Utc}; use serde::{Deserialize, Serialize}; -use tera::Tera; use serde_json::Value; +use tera::Tera; +use crate::db::calendar::{ + add_event_to_calendar, create_new_event, delete_event, get_events, get_or_create_user_calendar, +}; use crate::models::{CalendarEvent, CalendarViewMode}; -use crate::utils::{RedisCalendarService, render_template}; +use crate::utils::render_template; +use heromodels_core::Model; /// Controller for handling calendar-related routes pub struct CalendarController; @@ -14,9 +18,11 @@ pub struct CalendarController; impl CalendarController { /// Helper function to get user from session fn get_user_from_session(session: &Session) -> Option { - session.get::("user").ok().flatten().and_then(|user_json| { - serde_json::from_str(&user_json).ok() - }) + session + .get::("user") + .ok() + .flatten() + .and_then(|user_json| serde_json::from_str(&user_json).ok()) } /// Handles the calendar page route @@ -27,113 +33,186 @@ impl CalendarController { ) -> Result { let mut ctx = tera::Context::new(); ctx.insert("active_page", "calendar"); - + // Parse the view mode from the query parameters - let view_mode = CalendarViewMode::from_str(&query.view.clone().unwrap_or_else(|| "month".to_string())); + let view_mode = + CalendarViewMode::from_str(&query.view.clone().unwrap_or_else(|| "month".to_string())); ctx.insert("view_mode", &view_mode.to_str()); - + // Parse the date from the query parameters or use the current date let date = if let Some(date_str) = &query.date { match NaiveDate::parse_from_str(date_str, "%Y-%m-%d") { - Ok(naive_date) => Utc.from_utc_datetime(&naive_date.and_hms_opt(0, 0, 0).unwrap()).into(), + Ok(naive_date) => Utc + .from_utc_datetime(&naive_date.and_hms_opt(0, 0, 0).unwrap()) + .into(), Err(_) => Utc::now(), } } else { Utc::now() }; - + ctx.insert("current_date", &date.format("%Y-%m-%d").to_string()); ctx.insert("current_year", &date.year()); ctx.insert("current_month", &date.month()); ctx.insert("current_day", &date.day()); - - // Add user to context if available + + // Add user to context if available and ensure user has a calendar if let Some(user) = Self::get_user_from_session(&_session) { ctx.insert("user", &user); + + // Get or create user calendar + if let (Some(user_id), Some(user_name)) = ( + user.get("id").and_then(|v| v.as_u64()).map(|v| v as u32), + user.get("full_name").and_then(|v| v.as_str()), + ) { + match get_or_create_user_calendar(user_id, user_name) { + Ok(calendar) => { + log::info!( + "User calendar ready: ID {}, Name: '{}'", + calendar.get_id(), + calendar.name + ); + ctx.insert("user_calendar", &calendar); + } + Err(e) => { + log::error!("Failed to get or create user calendar: {}", e); + // Continue without calendar - the app should still work + } + } + } } - + // Get events for the current view let (start_date, end_date) = match view_mode { CalendarViewMode::Year => { let start = Utc.with_ymd_and_hms(date.year(), 1, 1, 0, 0, 0).unwrap(); - let end = Utc.with_ymd_and_hms(date.year(), 12, 31, 23, 59, 59).unwrap(); + let end = Utc + .with_ymd_and_hms(date.year(), 12, 31, 23, 59, 59) + .unwrap(); (start, end) - }, + } CalendarViewMode::Month => { - let start = Utc.with_ymd_and_hms(date.year(), date.month(), 1, 0, 0, 0).unwrap(); + let start = Utc + .with_ymd_and_hms(date.year(), date.month(), 1, 0, 0, 0) + .unwrap(); let last_day = Self::last_day_of_month(date.year(), date.month()); - let end = Utc.with_ymd_and_hms(date.year(), date.month(), last_day, 23, 59, 59).unwrap(); + let end = Utc + .with_ymd_and_hms(date.year(), date.month(), last_day, 23, 59, 59) + .unwrap(); (start, end) - }, + } CalendarViewMode::Week => { // Calculate the start of the week (Sunday) let _weekday = date.weekday().num_days_from_sunday(); - let start_date = date.date_naive().pred_opt().unwrap().pred_opt().unwrap().pred_opt().unwrap().pred_opt().unwrap().pred_opt().unwrap().pred_opt().unwrap().pred_opt().unwrap(); + let start_date = date + .date_naive() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap() + .pred_opt() + .unwrap(); let start = Utc.from_utc_datetime(&start_date.and_hms_opt(0, 0, 0).unwrap()); let end = start + chrono::Duration::days(7); (start, end) - }, + } CalendarViewMode::Day => { - let start = Utc.with_ymd_and_hms(date.year(), date.month(), date.day(), 0, 0, 0).unwrap(); - let end = Utc.with_ymd_and_hms(date.year(), date.month(), date.day(), 23, 59, 59).unwrap(); + let start = Utc + .with_ymd_and_hms(date.year(), date.month(), date.day(), 0, 0, 0) + .unwrap(); + let end = Utc + .with_ymd_and_hms(date.year(), date.month(), date.day(), 23, 59, 59) + .unwrap(); (start, end) - }, + } }; - - // Get events from Redis - let events = match RedisCalendarService::get_events_in_range(start_date, end_date) { - Ok(events) => events, + + // Get events from database + let events = match get_events() { + Ok(db_events) => { + // Filter events for the date range and convert to CalendarEvent format + db_events + .into_iter() + .filter(|event| { + // Event overlaps with the date range + event.start_time < end_date && event.end_time > start_date + }) + .map(|event| CalendarEvent { + id: event.get_id().to_string(), + title: event.title.clone(), + description: event.description.clone().unwrap_or_default(), + start_time: event.start_time, + end_time: event.end_time, + color: event.color.clone().unwrap_or_else(|| "#4285F4".to_string()), + all_day: event.all_day, + user_id: event.created_by.map(|id| id.to_string()), + }) + .collect() + } Err(e) => { - log::error!("Failed to get events from Redis: {}", e); + log::error!("Failed to get events from database: {}", e); vec![] } }; - + ctx.insert("events", &events); - + // Generate calendar data based on the view mode match view_mode { CalendarViewMode::Year => { - let months = (1..=12).map(|month| { - let month_name = match month { - 1 => "January", - 2 => "February", - 3 => "March", - 4 => "April", - 5 => "May", - 6 => "June", - 7 => "July", - 8 => "August", - 9 => "September", - 10 => "October", - 11 => "November", - 12 => "December", - _ => "", - }; - - let month_events = events.iter() - .filter(|event| { - event.start_time.month() == month || event.end_time.month() == month - }) - .cloned() - .collect::>(); - - CalendarMonth { - month, - name: month_name.to_string(), - events: month_events, - } - }).collect::>(); - + let months = (1..=12) + .map(|month| { + let month_name = match month { + 1 => "January", + 2 => "February", + 3 => "March", + 4 => "April", + 5 => "May", + 6 => "June", + 7 => "July", + 8 => "August", + 9 => "September", + 10 => "October", + 11 => "November", + 12 => "December", + _ => "", + }; + + let month_events = events + .iter() + .filter(|event| { + event.start_time.month() == month || event.end_time.month() == month + }) + .cloned() + .collect::>(); + + CalendarMonth { + month, + name: month_name.to_string(), + events: month_events, + } + }) + .collect::>(); + ctx.insert("months", &months); - }, + } CalendarViewMode::Month => { let days_in_month = Self::last_day_of_month(date.year(), date.month()); - let first_day = Utc.with_ymd_and_hms(date.year(), date.month(), 1, 0, 0, 0).unwrap(); + let first_day = Utc + .with_ymd_and_hms(date.year(), date.month(), 1, 0, 0, 0) + .unwrap(); let first_weekday = first_day.weekday().num_days_from_sunday(); - + let mut calendar_days = Vec::new(); - + // Add empty days for the start of the month for _ in 0..first_weekday { calendar_days.push(CalendarDay { @@ -142,27 +221,34 @@ impl CalendarController { is_current_month: false, }); } - + // Add days for the current month for day in 1..=days_in_month { - let day_events = events.iter() + let day_events = events + .iter() .filter(|event| { - let day_start = Utc.with_ymd_and_hms(date.year(), date.month(), day, 0, 0, 0).unwrap(); - let day_end = Utc.with_ymd_and_hms(date.year(), date.month(), day, 23, 59, 59).unwrap(); - - (event.start_time <= day_end && event.end_time >= day_start) || - (event.all_day && event.start_time.day() <= day && event.end_time.day() >= day) + let day_start = Utc + .with_ymd_and_hms(date.year(), date.month(), day, 0, 0, 0) + .unwrap(); + let day_end = Utc + .with_ymd_and_hms(date.year(), date.month(), day, 23, 59, 59) + .unwrap(); + + (event.start_time <= day_end && event.end_time >= day_start) + || (event.all_day + && event.start_time.day() <= day + && event.end_time.day() >= day) }) .cloned() .collect::>(); - + calendar_days.push(CalendarDay { day, events: day_events, is_current_month: true, }); } - + // Fill out the rest of the calendar grid (6 rows of 7 days) let remaining_days = 42 - calendar_days.len(); for day in 1..=remaining_days { @@ -172,149 +258,250 @@ impl CalendarController { is_current_month: false, }); } - + ctx.insert("calendar_days", &calendar_days); ctx.insert("month_name", &Self::month_name(date.month())); - }, + } CalendarViewMode::Week => { // Calculate the start of the week (Sunday) let weekday = date.weekday().num_days_from_sunday(); let week_start = date - chrono::Duration::days(weekday as i64); - + let mut week_days = Vec::new(); for i in 0..7 { let day_date = week_start + chrono::Duration::days(i); - let day_events = events.iter() + let day_events = events + .iter() .filter(|event| { - let day_start = Utc.with_ymd_and_hms(day_date.year(), day_date.month(), day_date.day(), 0, 0, 0).unwrap(); - let day_end = Utc.with_ymd_and_hms(day_date.year(), day_date.month(), day_date.day(), 23, 59, 59).unwrap(); - - (event.start_time <= day_end && event.end_time >= day_start) || - (event.all_day && event.start_time.day() <= day_date.day() && event.end_time.day() >= day_date.day()) + let day_start = Utc + .with_ymd_and_hms( + day_date.year(), + day_date.month(), + day_date.day(), + 0, + 0, + 0, + ) + .unwrap(); + let day_end = Utc + .with_ymd_and_hms( + day_date.year(), + day_date.month(), + day_date.day(), + 23, + 59, + 59, + ) + .unwrap(); + + (event.start_time <= day_end && event.end_time >= day_start) + || (event.all_day + && event.start_time.day() <= day_date.day() + && event.end_time.day() >= day_date.day()) }) .cloned() .collect::>(); - + week_days.push(CalendarDay { day: day_date.day(), events: day_events, is_current_month: day_date.month() == date.month(), }); } - + ctx.insert("week_days", &week_days); - }, + } CalendarViewMode::Day => { log::info!("Day view selected"); - ctx.insert("day_name", &Self::day_name(date.weekday().num_days_from_sunday())); - + ctx.insert( + "day_name", + &Self::day_name(date.weekday().num_days_from_sunday()), + ); + // Add debug info log::info!("Events count: {}", events.len()); log::info!("Current date: {}", date.format("%Y-%m-%d")); - log::info!("Day name: {}", Self::day_name(date.weekday().num_days_from_sunday())); - }, + log::info!( + "Day name: {}", + Self::day_name(date.weekday().num_days_from_sunday()) + ); + } } - + render_template(&tmpl, "calendar/index.html", &ctx) } - + /// Handles the new event page route pub async fn new_event(tmpl: web::Data, _session: Session) -> Result { let mut ctx = tera::Context::new(); ctx.insert("active_page", "calendar"); - - // Add user to context if available + + // Add user to context if available and ensure user has a calendar if let Some(user) = Self::get_user_from_session(&_session) { ctx.insert("user", &user); + + // Get or create user calendar + if let (Some(user_id), Some(user_name)) = ( + user.get("id").and_then(|v| v.as_u64()).map(|v| v as u32), + user.get("full_name").and_then(|v| v.as_str()), + ) { + match get_or_create_user_calendar(user_id, user_name) { + Ok(calendar) => { + ctx.insert("user_calendar", &calendar); + } + Err(e) => { + log::error!("Failed to get or create user calendar: {}", e); + } + } + } } - + render_template(&tmpl, "calendar/new_event.html", &ctx) } - + /// Handles the create event route pub async fn create_event( form: web::Form, tmpl: web::Data, _session: Session, ) -> Result { + // Log the form data for debugging + log::info!( + "Creating event with form data: title='{}', start_time='{}', end_time='{}', all_day={}", + form.title, + form.start_time, + form.end_time, + form.all_day + ); + // Parse the start and end times let start_time = match DateTime::parse_from_rfc3339(&form.start_time) { Ok(dt) => dt.with_timezone(&Utc), Err(e) => { - log::error!("Failed to parse start time: {}", e); - return Ok(HttpResponse::BadRequest().body("Invalid start time")); + log::error!("Failed to parse start time '{}': {}", form.start_time, e); + return Ok(HttpResponse::BadRequest().body("Invalid start time format")); } }; - + let end_time = match DateTime::parse_from_rfc3339(&form.end_time) { Ok(dt) => dt.with_timezone(&Utc), Err(e) => { - log::error!("Failed to parse end time: {}", e); - return Ok(HttpResponse::BadRequest().body("Invalid end time")); + log::error!("Failed to parse end time '{}': {}", form.end_time, e); + return Ok(HttpResponse::BadRequest().body("Invalid end time format")); } }; - - // Create the event - let event = CalendarEvent::new( - form.title.clone(), - form.description.clone(), + + // Get user information from session + let user_info = Self::get_user_from_session(&_session); + let (user_id, user_name) = if let Some(user) = &user_info { + let id = user.get("id").and_then(|v| v.as_u64()).map(|v| v as u32); + let name = user + .get("full_name") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown User"); + log::info!("User from session: id={:?}, name='{}'", id, name); + (id, name) + } else { + log::warn!("No user found in session"); + (None, "Unknown User") + }; + + // Create the event in the database + match create_new_event( + &form.title, + Some(&form.description), start_time, end_time, - Some(form.color.clone()), + None, // location + Some(&form.color), form.all_day, - None, // User ID would come from session in a real app - ); - - // Save the event to Redis - match RedisCalendarService::save_event(&event) { - Ok(_) => { + user_id, + None, // category + None, // reminder_minutes + ) { + Ok((event_id, _saved_event)) => { + log::info!("Created event with ID: {}", event_id); + + // If user is logged in, add the event to their calendar + if let Some(user_id) = user_id { + match get_or_create_user_calendar(user_id, user_name) { + Ok(calendar) => match add_event_to_calendar(calendar.get_id(), event_id) { + Ok(_) => { + log::info!( + "Added event {} to calendar {}", + event_id, + calendar.get_id() + ); + } + Err(e) => { + log::error!("Failed to add event to calendar: {}", e); + } + }, + Err(e) => { + log::error!("Failed to get user calendar: {}", e); + } + } + } + // Redirect to the calendar page Ok(HttpResponse::SeeOther() .append_header(("Location", "/calendar")) .finish()) - }, + } Err(e) => { - log::error!("Failed to save event to Redis: {}", e); - + log::error!("Failed to save event to database: {}", e); + // Show an error message let mut ctx = tera::Context::new(); ctx.insert("active_page", "calendar"); ctx.insert("error", "Failed to save event"); - + // Add user to context if available - if let Some(user) = Self::get_user_from_session(&_session) { + if let Some(user) = user_info { ctx.insert("user", &user); } - + let result = render_template(&tmpl, "calendar/new_event.html", &ctx)?; - - Ok(HttpResponse::InternalServerError().content_type("text/html").body(result.into_body())) + + Ok(HttpResponse::InternalServerError() + .content_type("text/html") + .body(result.into_body())) } } } - + /// Handles the delete event route pub async fn delete_event( path: web::Path, _session: Session, ) -> Result { let id = path.into_inner(); - - // Delete the event from Redis - match RedisCalendarService::delete_event(&id) { + + // Parse the event ID + let event_id = match id.parse::() { + Ok(id) => id, + Err(_) => { + log::error!("Invalid event ID: {}", id); + return Ok(HttpResponse::BadRequest().body("Invalid event ID")); + } + }; + + // Delete the event from database + match delete_event(event_id) { Ok(_) => { + log::info!("Deleted event with ID: {}", event_id); // Redirect to the calendar page Ok(HttpResponse::SeeOther() .append_header(("Location", "/calendar")) .finish()) - }, + } Err(e) => { - log::error!("Failed to delete event from Redis: {}", e); + log::error!("Failed to delete event from database: {}", e); Ok(HttpResponse::InternalServerError().body("Failed to delete event")) } } } - + /// Returns the last day of the month fn last_day_of_month(year: i32, month: u32) -> u32 { match month { @@ -326,11 +513,11 @@ impl CalendarController { } else { 28 } - }, + } _ => 30, // Default to 30 days } } - + /// Returns the name of the month fn month_name(month: u32) -> &'static str { match month { @@ -349,7 +536,7 @@ impl CalendarController { _ => "", } } - + /// Returns the name of the day fn day_name(day: u32) -> &'static str { match day { @@ -397,4 +584,4 @@ struct CalendarMonth { month: u32, name: String, events: Vec, -} \ No newline at end of file +} diff --git a/actix_mvc_app/src/db/calendar.rs b/actix_mvc_app/src/db/calendar.rs index e69de29..b71458c 100644 --- a/actix_mvc_app/src/db/calendar.rs +++ b/actix_mvc_app/src/db/calendar.rs @@ -0,0 +1,360 @@ +use chrono::{DateTime, Utc}; +use heromodels::{ + db::{Collection, Db}, + models::calendar::{AttendanceStatus, Attendee, Calendar, Event, EventStatus}, +}; + +use super::db::get_db; + +/// Creates a new calendar and saves it to the database. Returns the saved calendar and its ID. +pub fn create_new_calendar( + name: &str, + description: Option<&str>, + owner_id: Option, + is_public: bool, + color: Option<&str>, +) -> Result<(u32, Calendar), String> { + let db = get_db().expect("Can get DB"); + + // Create a new calendar (with auto-generated ID) + let mut calendar = Calendar::new(None, name); + + if let Some(desc) = description { + calendar = calendar.description(desc); + } + if let Some(owner) = owner_id { + calendar = calendar.owner_id(owner); + } + if let Some(col) = color { + calendar = calendar.color(col); + } + + calendar = calendar.is_public(is_public); + + // Save the calendar to the database + let collection = db + .collection::() + .expect("can open calendar collection"); + let (calendar_id, saved_calendar) = collection.set(&calendar).expect("can save calendar"); + + Ok((calendar_id, saved_calendar)) +} + +/// Creates a new event and saves it to the database. Returns the saved event and its ID. +pub fn create_new_event( + title: &str, + description: Option<&str>, + start_time: DateTime, + end_time: DateTime, + location: Option<&str>, + color: Option<&str>, + all_day: bool, + created_by: Option, + category: Option<&str>, + reminder_minutes: Option, +) -> Result<(u32, Event), String> { + let db = get_db().expect("Can get DB"); + + // Create a new event (with auto-generated ID) + let mut event = Event::new(title, start_time, end_time); + + if let Some(desc) = description { + event = event.description(desc); + } + if let Some(loc) = location { + event = event.location(loc); + } + if let Some(col) = color { + event = event.color(col); + } + if let Some(user_id) = created_by { + event = event.created_by(user_id); + } + if let Some(cat) = category { + event = event.category(cat); + } + if let Some(reminder) = reminder_minutes { + event = event.reminder_minutes(reminder); + } + + event = event.all_day(all_day); + + // Save the event to the database + let collection = db.collection::().expect("can open event collection"); + let (event_id, saved_event) = collection.set(&event).expect("can save event"); + + Ok((event_id, saved_event)) +} + +/// Loads all calendars from the database and returns them as a Vec. +pub fn get_calendars() -> Result, String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .expect("can open calendar collection"); + + // Try to load all calendars, but handle deserialization errors gracefully + let calendars = match collection.get_all() { + Ok(calendars) => calendars, + Err(e) => { + eprintln!("Error loading calendars: {:?}", e); + vec![] // Return an empty vector if there's an error + } + }; + Ok(calendars) +} + +/// Loads all events from the database and returns them as a Vec. +pub fn get_events() -> Result, String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db.collection::().expect("can open event collection"); + + // Try to load all events, but handle deserialization errors gracefully + let events = match collection.get_all() { + Ok(events) => events, + Err(e) => { + eprintln!("Error loading events: {:?}", e); + vec![] // Return an empty vector if there's an error + } + }; + Ok(events) +} + +/// Fetches a single calendar by its ID from the database. +pub fn get_calendar_by_id(calendar_id: u32) -> Result, String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + match collection.get_by_id(calendar_id) { + Ok(calendar) => Ok(calendar), + Err(e) => { + eprintln!("Error fetching calendar by id {}: {:?}", calendar_id, e); + Err(format!("Failed to fetch calendar: {:?}", e)) + } + } +} + +/// Fetches a single event by its ID from the database. +pub fn get_event_by_id(event_id: u32) -> Result, String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + match collection.get_by_id(event_id) { + Ok(event) => Ok(event), + Err(e) => { + eprintln!("Error fetching event by id {}: {:?}", event_id, e); + Err(format!("Failed to fetch event: {:?}", e)) + } + } +} + +/// Creates a new attendee and saves it to the database. Returns the saved attendee and its ID. +pub fn create_new_attendee( + contact_id: u32, + status: AttendanceStatus, +) -> Result<(u32, Attendee), String> { + let db = get_db().expect("Can get DB"); + + // Create a new attendee (with auto-generated ID) + let attendee = Attendee::new(contact_id).status(status); + + // Save the attendee to the database + let collection = db + .collection::() + .expect("can open attendee collection"); + let (attendee_id, saved_attendee) = collection.set(&attendee).expect("can save attendee"); + + Ok((attendee_id, saved_attendee)) +} + +/// Fetches a single attendee by its ID from the database. +pub fn get_attendee_by_id(attendee_id: u32) -> Result, String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + match collection.get_by_id(attendee_id) { + Ok(attendee) => Ok(attendee), + Err(e) => { + eprintln!("Error fetching attendee by id {}: {:?}", attendee_id, e); + Err(format!("Failed to fetch attendee: {:?}", e)) + } + } +} + +/// Updates attendee status in the database and returns the updated attendee. +pub fn update_attendee_status( + attendee_id: u32, + status: AttendanceStatus, +) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + if let Some(mut attendee) = collection + .get_by_id(attendee_id) + .map_err(|e| format!("Failed to fetch attendee: {:?}", e))? + { + attendee = attendee.status(status); + let (_, updated_attendee) = collection + .set(&attendee) + .map_err(|e| format!("Failed to update attendee: {:?}", e))?; + Ok(updated_attendee) + } else { + Err("Attendee not found".to_string()) + } +} + +/// Add attendee to event +pub fn add_attendee_to_event(event_id: u32, attendee_id: u32) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + if let Some(mut event) = collection + .get_by_id(event_id) + .map_err(|e| format!("Failed to fetch event: {:?}", e))? + { + event = event.add_attendee(attendee_id); + let (_, updated_event) = collection + .set(&event) + .map_err(|e| format!("Failed to update event: {:?}", e))?; + Ok(updated_event) + } else { + Err("Event not found".to_string()) + } +} + +/// Remove attendee from event +pub fn remove_attendee_from_event(event_id: u32, attendee_id: u32) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + if let Some(mut event) = collection + .get_by_id(event_id) + .map_err(|e| format!("Failed to fetch event: {:?}", e))? + { + event = event.remove_attendee(attendee_id); + let (_, updated_event) = collection + .set(&event) + .map_err(|e| format!("Failed to update event: {:?}", e))?; + Ok(updated_event) + } else { + Err("Event not found".to_string()) + } +} + +/// Add event to calendar +pub fn add_event_to_calendar(calendar_id: u32, event_id: u32) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + if let Some(mut calendar) = collection + .get_by_id(calendar_id) + .map_err(|e| format!("Failed to fetch calendar: {:?}", e))? + { + calendar = calendar.add_event(event_id as i64); + let (_, updated_calendar) = collection + .set(&calendar) + .map_err(|e| format!("Failed to update calendar: {:?}", e))?; + Ok(updated_calendar) + } else { + Err("Calendar not found".to_string()) + } +} + +/// Remove event from calendar +pub fn remove_event_from_calendar(calendar_id: u32, event_id: u32) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + if let Some(mut calendar) = collection + .get_by_id(calendar_id) + .map_err(|e| format!("Failed to fetch calendar: {:?}", e))? + { + calendar = calendar.remove_event(event_id as i64); + let (_, updated_calendar) = collection + .set(&calendar) + .map_err(|e| format!("Failed to update calendar: {:?}", e))?; + Ok(updated_calendar) + } else { + Err("Calendar not found".to_string()) + } +} + +/// Deletes a calendar from the database. +pub fn delete_calendar(calendar_id: u32) -> Result<(), String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + collection + .delete_by_id(calendar_id) + .map_err(|e| format!("Failed to delete calendar: {:?}", e))?; + + Ok(()) +} + +/// Deletes an event from the database. +pub fn delete_event(event_id: u32) -> Result<(), String> { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + collection + .delete_by_id(event_id) + .map_err(|e| format!("Failed to delete event: {:?}", e))?; + + Ok(()) +} + +/// Gets or creates a calendar for a user. If the user already has a calendar, returns it. +/// If not, creates a new calendar for the user and returns it. +pub fn get_or_create_user_calendar(user_id: u32, user_name: &str) -> Result { + let db = get_db().map_err(|e| format!("DB error: {}", e))?; + let collection = db + .collection::() + .map_err(|e| format!("Collection error: {:?}", e))?; + + // Try to find existing calendar for this user + let calendars = match collection.get_all() { + Ok(calendars) => calendars, + Err(e) => { + eprintln!("Error loading calendars: {:?}", e); + vec![] // Return an empty vector if there's an error + } + }; + + // Look for a calendar owned by this user + for calendar in calendars { + if let Some(owner_id) = calendar.owner_id { + if owner_id == user_id { + return Ok(calendar); + } + } + } + + // No calendar found for this user, create a new one + let calendar_name = format!("{}'s Calendar", user_name); + let (_, new_calendar) = create_new_calendar( + &calendar_name, + Some("Personal calendar"), + Some(user_id), + false, // Private calendar + Some("#4285F4"), // Default blue color + )?; + + Ok(new_calendar) +} diff --git a/actix_mvc_app/src/db/mod.rs b/actix_mvc_app/src/db/mod.rs index cfe9423..0b27adf 100644 --- a/actix_mvc_app/src/db/mod.rs +++ b/actix_mvc_app/src/db/mod.rs @@ -1,2 +1,3 @@ +pub mod calendar; pub mod db; pub mod governance; diff --git a/actix_mvc_app/src/views/calendar/index.html b/actix_mvc_app/src/views/calendar/index.html index 1b98ca1..1bc8aed 100644 --- a/actix_mvc_app/src/views/calendar/index.html +++ b/actix_mvc_app/src/views/calendar/index.html @@ -13,8 +13,7 @@

Manage your events and schedule

-
@@ -245,6 +244,14 @@