diff --git a/geneit_backend/src/controllers/accommodations_reservations_controller.rs b/geneit_backend/src/controllers/accommodations_reservations_controller.rs index 3159d3a..de15350 100644 --- a/geneit_backend/src/controllers/accommodations_reservations_controller.rs +++ b/geneit_backend/src/controllers/accommodations_reservations_controller.rs @@ -2,50 +2,67 @@ use crate::controllers::HttpResult; use crate::extractors::accommodation_extractor::FamilyAndAccommodationInPath; use crate::extractors::accommodation_reservation_extractor::FamilyAndAccommodationReservationInPath; use crate::extractors::family_extractor::FamilyInPath; -use crate::models::NewAccommodationReservation; +use crate::models::{Accommodation, AccommodationReservationID, NewAccommodationReservation}; use crate::services::accommodations_reservations_service; use crate::utils::time_utils::time; use actix_web::{web, HttpResponse}; #[derive(serde::Deserialize)] -pub struct CreateReservationQuery { +pub struct UpdateReservationQuery { start: usize, end: usize, } +impl UpdateReservationQuery { + /// Check whether a reservation request is valid or not + async fn validate( + &self, + a: &Accommodation, + resa_id: Option, + ) -> anyhow::Result> { + if !a.open_to_reservations { + return Ok(Some( + "The accommodation is not open to reservations create / update!", + )); + } + + if (self.start as i64) < (time() as i64 - 3600 * 24 * 30) { + return Ok(Some("Start time is too far in the past!")); + } + + if self.start == self.end { + return Ok(Some("Start and end time must be different!")); + } + + if self.start > self.end { + return Ok(Some("End time happens before start time!")); + } + + let existing = accommodations_reservations_service::get_reservations_for_time_interval( + a.id(), + self.start, + self.end, + ) + .await?; + + if existing + .iter() + .any(|r| r.validated != Some(false) && resa_id != Some(r.id())) + { + return Ok(Some("This reservation is in conflict with another one!")); + } + + Ok(None) + } +} + /// Create a reservation pub async fn create_reservation( a: FamilyAndAccommodationInPath, - req: web::Json, + req: web::Json, ) -> HttpResult { - if !a.open_to_reservations { - return Ok(HttpResponse::ExpectationFailed() - .json("The accommodation is not open to reservations!")); - } - - if (req.start as i64) < (time() as i64 - 3600 * 24 * 30) { - return Ok(HttpResponse::BadRequest().json("Start time is too far in the past!")); - } - - if req.start == req.end { - return Ok(HttpResponse::BadRequest().json("Start and end time must be different!")); - } - - if req.start > req.end { - return Ok(HttpResponse::BadRequest().json("End time happens before start time!")); - } - - let existing = accommodations_reservations_service::get_reservations_for_time_interval( - a.id(), - req.start, - req.end, - ) - .await?; - - if existing.iter().any(|r| r.validated != Some(false)) { - return Ok( - HttpResponse::Conflict().json("This reservation is in conflict with another one!") - ); + if let Some(err) = req.validate(&a, None).await? { + return Ok(HttpResponse::BadRequest().json(err)); } let mut reservation = @@ -87,6 +104,36 @@ pub async fn get_single(m: FamilyAndAccommodationReservationInPath) -> HttpResul Ok(HttpResponse::Ok().json(m.to_reservation())) } +/// Update a reservation +pub async fn update_single( + m: FamilyAndAccommodationReservationInPath, + req: web::Json, +) -> HttpResult { + if let Some(err) = req.validate(m.as_accommodation(), Some(m.id())).await? { + return Ok(HttpResponse::BadRequest().json(err)); + } + + if m.membership().user_id() != m.user_id() { + return Ok( + HttpResponse::BadRequest().json("Only the owner of a reservation can change it!") + ); + } + + let need_validation = m.as_accommodation().need_validation; + + let mut reservation = m.to_reservation(); + reservation.reservation_start = req.start as i64; + reservation.reservation_end = req.end as i64; + + if need_validation { + reservation.validated = None; + } + + accommodations_reservations_service::update(&mut reservation).await?; + + Ok(HttpResponse::Accepted().finish()) +} + /// Delete a reservation pub async fn delete(m: FamilyAndAccommodationReservationInPath) -> HttpResult { if m.membership().user_id() != m.user_id() { diff --git a/geneit_backend/src/extractors/accommodation_reservation_extractor.rs b/geneit_backend/src/extractors/accommodation_reservation_extractor.rs index 483028f..d62d63c 100644 --- a/geneit_backend/src/extractors/accommodation_reservation_extractor.rs +++ b/geneit_backend/src/extractors/accommodation_reservation_extractor.rs @@ -60,6 +60,10 @@ impl FamilyAndAccommodationReservationInPath { &self.0 } + pub fn as_accommodation(&self) -> &Accommodation { + &self.1 + } + pub fn to_accommodation(self) -> Accommodation { self.1 } diff --git a/geneit_backend/src/main.rs b/geneit_backend/src/main.rs index f9c0250..5799638 100644 --- a/geneit_backend/src/main.rs +++ b/geneit_backend/src/main.rs @@ -244,7 +244,10 @@ async fn main() -> std::io::Result<()> { "/family/{id}/accommodations/reservation/{reservation_id}", web::get().to(accommodations_reservations_controller::get_single), ) - // TODO : update + .route( + "/family/{id}/accommodations/reservation/{reservation_id}", + web::patch().to(accommodations_reservations_controller::update_single), + ) .route( "/family/{id}/accommodations/reservation/{reservation_id}", web::delete().to(accommodations_reservations_controller::delete), diff --git a/geneit_backend/src/services/accommodations_reservations_service.rs b/geneit_backend/src/services/accommodations_reservations_service.rs index f3425cc..0cd018b 100644 --- a/geneit_backend/src/services/accommodations_reservations_service.rs +++ b/geneit_backend/src/services/accommodations_reservations_service.rs @@ -30,6 +30,8 @@ pub async fn update(r: &mut AccommodationReservation) -> anyhow::Result<()> { .set(( accommodations_reservations::dsl::time_update.eq(r.time_update), accommodations_reservations::dsl::validated.eq(r.validated), + accommodations_reservations::dsl::reservation_start.eq(r.reservation_start), + accommodations_reservations::dsl::reservation_end.eq(r.reservation_end), )) .execute(conn) })?;