Add an accommodations reservations module #188

Merged
pierre merged 81 commits from accomodation_module into master 2024-06-22 21:30:26 +00:00
3 changed files with 116 additions and 2 deletions
Showing only changes of commit 5f25a516e9 - Show all commits

View File

@ -2,8 +2,69 @@ 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::services::accommodations_reservations_service; 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<CreateReservationQuery>,
) -> 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 /// Get the reservations for a given accommodation
pub async fn get_accommodation_reservations(a: FamilyAndAccommodationInPath) -> HttpResult { pub async fn get_accommodation_reservations(a: FamilyAndAccommodationInPath) -> HttpResult {

View File

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

View File

@ -1,10 +1,42 @@
use crate::connections::db_connection; use crate::connections::db_connection;
use crate::models::{ use crate::models::{
AccommodationID, AccommodationReservation, AccommodationReservationID, FamilyID, AccommodationID, AccommodationReservation, AccommodationReservationID, FamilyID,
NewAccommodationReservation,
}; };
use crate::schema::accommodations_reservations; use crate::schema::accommodations_reservations;
use crate::utils::time_utils::time;
use diesel::prelude::*; use diesel::prelude::*;
/// Create a new reservation
pub async fn create(new: &NewAccommodationReservation) -> anyhow::Result<AccommodationReservation> {
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 /// Get all the reservations of an accommodation
pub async fn get_all_of_accommodation( pub async fn get_all_of_accommodation(
id: AccommodationID, id: AccommodationID,
@ -33,3 +65,21 @@ pub async fn get_by_id(id: AccommodationReservationID) -> anyhow::Result<Accommo
.get_result(conn) .get_result(conn)
}) })
} }
/// Get the reservations that are between a given interval of time for a given accommodation
pub async fn get_reservations_for_time_interval(
id: AccommodationID,
start: usize,
end: usize,
) -> anyhow::Result<Vec<AccommodationReservation>> {
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)
})
}