use crate::constants::StaticConstraints; use crate::controllers::HttpResult; use crate::extractors::accommodation_extractor::FamilyAndAccommodationInPath; use crate::extractors::family_extractor::{FamilyInPath, FamilyInPathWithAdminMembership}; use crate::models::Accommodation; use crate::services::accommodations_list_service; use actix_web::{web, HttpResponse}; #[derive(thiserror::Error, Debug)] enum AccommodationListControllerErr { #[error("Invalid name length!")] InvalidNameLength, #[error("Invalid description length!")] InvalidDescriptionLength, #[error("Malformed color!")] MalformedColor, } #[derive(serde::Deserialize, Clone)] pub struct AccommodationRequest { pub name: String, pub need_validation: bool, pub description: Option, pub color: Option, pub open_to_reservations: bool, } impl AccommodationRequest { pub async fn to_accommodation(self, accommodation: &mut Accommodation) -> anyhow::Result<()> { let c = StaticConstraints::default(); if !c.accommodation_name_len.validate(&self.name) { return Err(AccommodationListControllerErr::InvalidNameLength.into()); } accommodation.name = self.name; if let Some(d) = &self.description { if !c.accommodation_description_len.validate(d) { return Err(AccommodationListControllerErr::InvalidDescriptionLength.into()); } } accommodation.description.clone_from(&self.description); if let Some(c) = &self.color { if !lazy_regex::regex!("[a-fA-F0-9]{6}").is_match(c) { return Err(AccommodationListControllerErr::MalformedColor.into()); } } accommodation.color.clone_from(&self.color); accommodation.need_validation = self.need_validation; accommodation.open_to_reservations = self.open_to_reservations; Ok(()) } } /// Create a new accommodation pub async fn create( m: FamilyInPathWithAdminMembership, req: web::Json, ) -> HttpResult { let mut accommodation = accommodations_list_service::create(m.family_id()).await?; if let Err(e) = req.0.to_accommodation(&mut accommodation).await { log::error!("Failed to apply accommodation information! {e}"); accommodations_list_service::delete(&mut accommodation).await?; return Ok(HttpResponse::BadRequest().body(e.to_string())); } if let Err(e) = accommodations_list_service::update(&mut accommodation).await { log::error!("Failed to update accommodation information! {e}"); accommodations_list_service::delete(&mut accommodation).await?; return Ok(HttpResponse::InternalServerError().finish()); } Ok(HttpResponse::Ok().json(accommodation)) } /// Get the full list of accommodations pub async fn get_full_list(m: FamilyInPath) -> HttpResult { Ok(HttpResponse::Ok() .json(accommodations_list_service::get_all_of_family(m.family_id()).await?)) } /// Get the information of a single accommodation pub async fn get_single(m: FamilyAndAccommodationInPath) -> HttpResult { Ok(HttpResponse::Ok().json(&m.to_accommodation())) } /// Update an accommodation pub async fn update( m: FamilyAndAccommodationInPath, req: web::Json, _admin: FamilyInPathWithAdminMembership, ) -> HttpResult { let mut accommodation = m.to_accommodation(); if let Err(e) = req.0.to_accommodation(&mut accommodation).await { log::error!("Failed to parse accommodation information! {e}"); return Ok(HttpResponse::BadRequest().body(e.to_string())); } accommodations_list_service::update(&mut accommodation).await?; Ok(HttpResponse::Accepted().finish()) } /// Delete an accommodation pub async fn delete( m: FamilyAndAccommodationInPath, _admin: FamilyInPathWithAdminMembership, ) -> HttpResult { accommodations_list_service::delete(&mut m.to_accommodation()).await?; Ok(HttpResponse::Ok().finish()) }