use ical::{generator::*, *}; use actix_web::{web, HttpResponse}; use chrono::DateTime; use crate::constants::StaticConstraints; use crate::controllers::HttpResult; use crate::extractors::accommodation_reservation_calendar_extractor::FamilyAndAccommodationReservationCalendarInPath; use crate::extractors::family_extractor::FamilyInPath; use crate::models::{AccommodationID, ReservationStatus}; use crate::services::{ accommodations_list_service, accommodations_reservations_calendars_service, accommodations_reservations_service, families_service, }; #[derive(serde::Deserialize)] pub struct CreateCalendarQuery { accommodation_id: Option<AccommodationID>, name: String, } /// Create a calendar pub async fn create(a: FamilyInPath, req: web::Json<CreateCalendarQuery>) -> HttpResult { let accommodation_id = match req.accommodation_id { Some(i) => { let accommodation = match accommodations_list_service::get_by_id(i).await { Ok(a) => a, Err(e) => { log::error!("Failed to get accommodation information! {e}"); return Ok(HttpResponse::NotFound() .json("The accommodation was not found in the family!")); } }; if accommodation.family_id() != a.family_id() { return Ok( HttpResponse::NotFound().json("The accommodation was not found in the family!") ); } Some(accommodation.id()) } None => None, }; let conf = StaticConstraints::default(); if !conf.accommodation_calendar_name_len.validate(&req.name) { return Ok(HttpResponse::BadRequest().json("Invalid accommodation name!")); } let calendar = accommodations_reservations_calendars_service::create( a.user_id(), a.family_id(), accommodation_id, &req.name, ) .await?; Ok(HttpResponse::Ok().json(calendar)) } /// Get the list of calendars of a user pub async fn get_list(a: FamilyInPath) -> HttpResult { let users = accommodations_reservations_calendars_service::get_all_of_user(a.user_id(), a.family_id()) .await?; Ok(HttpResponse::Ok().json(users)) } /// Delete a calendar pub async fn delete(resa: FamilyAndAccommodationReservationCalendarInPath) -> HttpResult { accommodations_reservations_calendars_service::delete(resa.to_reservation()).await?; Ok(HttpResponse::Ok().json("Calendar successfully deleted")) } fn fmt_date(time: i64) -> String { let res = DateTime::from_timestamp(time, 0).expect("Failed to parse date"); /*format!( "{:0>4}{:0>2}{:0>2}T{:0>2}{:0>2}", res.year(), res.month(), res.day(), res.minute(), res.second() )*/ res.format("%Y%m%dT%H%M%S").to_string() } #[derive(serde::Deserialize)] pub struct AnonymousAccessURL { token: String, } /// Get the content of the calendar pub async fn anonymous_access(req: web::Path<AnonymousAccessURL>) -> HttpResult { let calendar = match accommodations_reservations_calendars_service::get_by_token(&req.token).await { Ok(c) => c, Err(e) => { log::error!("Calendar information could not be retrieved: {e}"); return Ok(HttpResponse::NotFound().body("Calendar not found!")); } }; let accommodations = accommodations_list_service::get_all_of_family(calendar.family_id()).await?; let members = families_service::get_memberships_of_family(calendar.family_id()).await?; // Get calendar associated events let events = match calendar.accommodation_id() { None => { accommodations_reservations_service::get_all_of_family(calendar.family_id()).await? } Some(a) => accommodations_reservations_service::get_all_of_accommodation(a).await?, }; let mut cal = IcalCalendarBuilder::version("2.0") .gregorian() .prodid("-//geneit//") .build(); for ev in events { let accommodation = accommodations .iter() .find(|a| a.id() == ev.accommodation_id()) .unwrap(); let member_name = members .iter() .find(|a| a.membership.user_id() == ev.user_id()) .map(|m| m.user_name.as_str()) .unwrap_or("other user"); let event = IcalEventBuilder::tzid("Europe/Paris") .uid(format!("resa-{}", ev.id().0)) .changed(fmt_date(ev.time_update)) .start(fmt_date(ev.reservation_start)) .end(fmt_date(ev.reservation_end)) .set(ical_property!("SUMMARY", member_name)) .set(ical_property!("LOCATION", &accommodation.name)) .set(ical_property!( "STATUS", match ev.status() { ReservationStatus::Pending => "TENTATIVE", ReservationStatus::Accepted => "CONFIRMED", ReservationStatus::Rejected => "CANCELLED", } )) .build(); cal.events.push(event); } Ok(HttpResponse::Ok() .content_type("text/calendar") .body(cal.generate())) }