Add an accommodations reservations module #188

Merged
pierre merged 81 commits from accomodation_module into master 2024-06-22 21:30:26 +00:00
4 changed files with 88 additions and 32 deletions
Showing only changes of commit f07a6a8923 - Show all commits

View File

@ -2,50 +2,67 @@ use crate::controllers::HttpResult;
use crate::extractors::accommodation_extractor::FamilyAndAccommodationInPath; use crate::extractors::accommodation_extractor::FamilyAndAccommodationInPath;
use crate::extractors::accommodation_reservation_extractor::FamilyAndAccommodationReservationInPath; use crate::extractors::accommodation_reservation_extractor::FamilyAndAccommodationReservationInPath;
use crate::extractors::family_extractor::FamilyInPath; use crate::extractors::family_extractor::FamilyInPath;
use crate::models::NewAccommodationReservation; use crate::models::{Accommodation, AccommodationReservationID, NewAccommodationReservation};
use crate::services::accommodations_reservations_service; use crate::services::accommodations_reservations_service;
use crate::utils::time_utils::time; use crate::utils::time_utils::time;
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct CreateReservationQuery { pub struct UpdateReservationQuery {
start: usize, start: usize,
end: usize, end: usize,
} }
impl UpdateReservationQuery {
/// Check whether a reservation request is valid or not
async fn validate(
&self,
a: &Accommodation,
resa_id: Option<AccommodationReservationID>,
) -> anyhow::Result<Option<&str>> {
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 /// Create a reservation
pub async fn create_reservation( pub async fn create_reservation(
a: FamilyAndAccommodationInPath, a: FamilyAndAccommodationInPath,
req: web::Json<CreateReservationQuery>, req: web::Json<UpdateReservationQuery>,
) -> HttpResult { ) -> HttpResult {
if !a.open_to_reservations { if let Some(err) = req.validate(&a, None).await? {
return Ok(HttpResponse::ExpectationFailed() return Ok(HttpResponse::BadRequest().json(err));
.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!")
);
} }
let mut reservation = let mut reservation =
@ -87,6 +104,36 @@ pub async fn get_single(m: FamilyAndAccommodationReservationInPath) -> HttpResul
Ok(HttpResponse::Ok().json(m.to_reservation())) Ok(HttpResponse::Ok().json(m.to_reservation()))
} }
/// Update a reservation
pub async fn update_single(
m: FamilyAndAccommodationReservationInPath,
req: web::Json<UpdateReservationQuery>,
) -> 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 /// Delete a reservation
pub async fn delete(m: FamilyAndAccommodationReservationInPath) -> HttpResult { pub async fn delete(m: FamilyAndAccommodationReservationInPath) -> HttpResult {
if m.membership().user_id() != m.user_id() { if m.membership().user_id() != m.user_id() {

View File

@ -60,6 +60,10 @@ impl FamilyAndAccommodationReservationInPath {
&self.0 &self.0
} }
pub fn as_accommodation(&self) -> &Accommodation {
&self.1
}
pub fn to_accommodation(self) -> Accommodation { pub fn to_accommodation(self) -> Accommodation {
self.1 self.1
} }

View File

@ -244,7 +244,10 @@ async fn main() -> std::io::Result<()> {
"/family/{id}/accommodations/reservation/{reservation_id}", "/family/{id}/accommodations/reservation/{reservation_id}",
web::get().to(accommodations_reservations_controller::get_single), 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( .route(
"/family/{id}/accommodations/reservation/{reservation_id}", "/family/{id}/accommodations/reservation/{reservation_id}",
web::delete().to(accommodations_reservations_controller::delete), web::delete().to(accommodations_reservations_controller::delete),

View File

@ -30,6 +30,8 @@ pub async fn update(r: &mut AccommodationReservation) -> anyhow::Result<()> {
.set(( .set((
accommodations_reservations::dsl::time_update.eq(r.time_update), accommodations_reservations::dsl::time_update.eq(r.time_update),
accommodations_reservations::dsl::validated.eq(r.validated), 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) .execute(conn)
})?; })?;