From 5f25a516e93ad962c6355f2cac38d046cc3a77e9 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 29 May 2024 22:16:50 +0200 Subject: [PATCH] Can create reservation requests --- .../accommodations_reservations_controller.rs | 63 ++++++++++++++++++- geneit_backend/src/main.rs | 5 +- .../accommodations_reservations_service.rs | 50 +++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/geneit_backend/src/controllers/accommodations_reservations_controller.rs b/geneit_backend/src/controllers/accommodations_reservations_controller.rs index 516f25f..1635ae3 100644 --- a/geneit_backend/src/controllers/accommodations_reservations_controller.rs +++ b/geneit_backend/src/controllers/accommodations_reservations_controller.rs @@ -2,8 +2,69 @@ 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::services::accommodations_reservations_service; -use actix_web::HttpResponse; +use crate::utils::time_utils::time; +use actix_web::{web, HttpResponse}; + +#[derive(serde::Deserialize)] +pub struct CreateReservationQuery { + start: usize, + end: usize, +} + +/// Create a reservation +pub async fn create_reservation( + a: FamilyAndAccommodationInPath, + 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("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!") + ); + } + + let mut reservation = + accommodations_reservations_service::create(&NewAccommodationReservation { + family_id: a.family_id().0, + accommodation_id: a.id().0, + user_id: a.membership().user_id().0, + time_create: time() as i64, + time_update: time() as i64, + reservation_start: req.start as i64, + reservation_end: req.end as i64, + }) + .await?; + + // Auto validate reservation if requested + if !a.need_validation { + reservation.validated = Some(true); + + accommodations_reservations_service::update(&mut reservation).await?; + } + + Ok(HttpResponse::Ok().json(reservation)) +} /// Get the reservations for a given accommodation pub async fn get_accommodation_reservations(a: FamilyAndAccommodationInPath) -> HttpResult { diff --git a/geneit_backend/src/main.rs b/geneit_backend/src/main.rs index 32c5f5e..3e898d3 100644 --- a/geneit_backend/src/main.rs +++ b/geneit_backend/src/main.rs @@ -236,7 +236,10 @@ async fn main() -> std::io::Result<()> { "/family/{id}/accommodations/reservations/full_list", web::get().to(accommodations_reservations_controller::full_list), ) - // TODO : create + .route( + "/family/{id}/accommodations/reservations/accommodation/{accommodation_id}/create", + web::post().to(accommodations_reservations_controller::create_reservation), + ) .route( "/family/{id}/accommodations/reservation/{reservation_id}", web::get().to(accommodations_reservations_controller::get_single), diff --git a/geneit_backend/src/services/accommodations_reservations_service.rs b/geneit_backend/src/services/accommodations_reservations_service.rs index 95dbf05..fa00c4a 100644 --- a/geneit_backend/src/services/accommodations_reservations_service.rs +++ b/geneit_backend/src/services/accommodations_reservations_service.rs @@ -1,10 +1,42 @@ use crate::connections::db_connection; use crate::models::{ AccommodationID, AccommodationReservation, AccommodationReservationID, FamilyID, + NewAccommodationReservation, }; use crate::schema::accommodations_reservations; +use crate::utils::time_utils::time; use diesel::prelude::*; +/// Create a new reservation +pub async fn create(new: &NewAccommodationReservation) -> anyhow::Result { + db_connection::execute(|conn| { + let res: AccommodationReservation = diesel::insert_into(accommodations_reservations::table) + .values(new) + .get_result(conn)?; + + Ok(res) + }) +} + +/// Update a reservation +pub async fn update(r: &mut AccommodationReservation) -> anyhow::Result<()> { + r.time_update = time() as i64; + + db_connection::execute(|conn| { + diesel::update( + accommodations_reservations::dsl::accommodations_reservations + .filter(accommodations_reservations::dsl::id.eq(r.id().0)), + ) + .set(( + accommodations_reservations::dsl::time_update.eq(r.time_update), + accommodations_reservations::dsl::validated.eq(r.validated), + )) + .execute(conn) + })?; + + Ok(()) +} + /// Get all the reservations of an accommodation pub async fn get_all_of_accommodation( id: AccommodationID, @@ -33,3 +65,21 @@ pub async fn get_by_id(id: AccommodationReservationID) -> anyhow::Result anyhow::Result> { + db_connection::execute(|conn| { + accommodations_reservations::table + .filter( + accommodations_reservations::dsl::accommodation_id + .eq(id.0) + .and(accommodations_reservations::dsl::reservation_start.lt((end) as i64)) + .and(accommodations_reservations::dsl::reservation_end.gt((start) as i64)), + ) + .get_results(conn) + }) +}