reservations
All checks were successful
CI/CD Pipeline / test (push) Successful in 11m11s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped

This commit is contained in:
2024-03-30 01:36:37 +01:00
parent 163c97b2f5
commit 649169c192
14 changed files with 490 additions and 10 deletions

View File

@ -0,0 +1,179 @@
use crate::model::{boat::Boat, user::User};
use chrono::NaiveDate;
use chrono::NaiveDateTime;
use rocket::serde::{Deserialize, Serialize};
use rocket::FromForm;
use sqlx::{FromRow, SqlitePool};
use super::log::Log;
use super::notification::Notification;
use super::role::Role;
#[derive(FromRow, Debug, Serialize, Deserialize)]
pub struct BoatReservation {
pub id: i64,
pub boat_id: i64,
pub start_date: NaiveDate,
pub end_date: NaiveDate,
pub time_desc: String,
pub usage: String,
pub user_id_applicant: i64,
pub user_id_confirmation: Option<i64>,
pub created_at: NaiveDateTime,
}
#[derive(FromRow, Debug, Serialize, Deserialize)]
pub struct BoatReservationWithDetails {
#[serde(flatten)]
boat_reservation: BoatReservation,
boat: Boat,
user_applicant: User,
user_confirmation: Option<User>,
}
#[derive(Debug)]
pub struct BoatReservationToAdd<'r> {
pub boat: &'r Boat,
pub start_date: NaiveDate,
pub end_date: NaiveDate,
pub time_desc: &'r str,
pub usage: &'r str,
pub user_applicant: &'r User,
}
impl BoatReservation {
pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
sqlx::query_as!(
Self,
"SELECT id, boat_id, start_date, end_date, time_desc, usage, user_id_applicant, user_id_confirmation, created_at
FROM boat_reservation
WHERE id like ?",
id
)
.fetch_one(db)
.await
.ok()
}
pub async fn all_future(db: &SqlitePool) -> Vec<BoatReservationWithDetails> {
let boatreservations = sqlx::query_as!(
Self,
"
SELECT id, boat_id, start_date, end_date, time_desc, usage, user_id_applicant, user_id_confirmation, created_at
FROM boat_reservation
WHERE end_date >= CURRENT_DATE ORDER BY end_date
"
)
.fetch_all(db)
.await
.unwrap(); //TODO: fixme
let mut res = Vec::new();
for reservation in boatreservations {
let user_confirmation = match reservation.user_id_confirmation {
Some(id) => {
let user = User::find_by_id(db, id as i32).await;
Some(user.unwrap())
}
None => None,
};
let user_applicant = User::find_by_id(db, reservation.user_id_applicant as i32)
.await
.unwrap();
let boat = Boat::find_by_id(db, reservation.boat_id as i32)
.await
.unwrap();
res.push(BoatReservationWithDetails {
boat_reservation: reservation,
boat,
user_applicant,
user_confirmation,
});
}
res
}
pub async fn create(
db: &SqlitePool,
boatreservation: BoatReservationToAdd<'_>,
) -> Result<(), String> {
if Self::boat_reserved_between_dates(
db,
boatreservation.boat,
&boatreservation.start_date,
&boatreservation.end_date,
)
.await
{
return Err("Boot in diesem Zeitraum bereits reserviert.".into());
}
Log::create(db, format!("New boat reservation: {boatreservation:?}")).await;
sqlx::query!(
"INSERT INTO boat_reservation(boat_id, start_date, end_date, time_desc, usage, user_id_applicant) VALUES (?,?,?,?,?,?)",
boatreservation.boat.id,
boatreservation.start_date,
boatreservation.end_date,
boatreservation.time_desc,
boatreservation.usage,
boatreservation.user_applicant.id,
)
.execute(db)
.await
.map_err(|e| e.to_string())?;
let board =
User::all_with_role(db, &Role::find_by_name(db, "Vorstand").await.unwrap()).await;
for user in board {
Notification::create(
db,
&user,
&format!(
"{} hat eine neue Bootsreservierung für Boot '{}' angelegt: Von {} bis {} um {} wegen {}",
boatreservation.user_applicant.name,
boatreservation.boat.name,
boatreservation.start_date,
boatreservation.end_date,
boatreservation.time_desc,
boatreservation.usage
),
"Neue Bootsreservierung",
None,
)
.await;
}
Ok(())
}
pub async fn boat_reserved_between_dates(
db: &SqlitePool,
boat: &Boat,
start_date: &NaiveDate,
end_date: &NaiveDate,
) -> bool {
sqlx::query!(
"SELECT COUNT(*) AS reservation_count
FROM boat_reservation
WHERE boat_id = ?
AND start_date <= ? AND end_date >= ?;",
boat.id,
end_date,
start_date
)
.fetch_one(db)
.await
.unwrap()
.reservation_count
> 0
}
pub async fn delete(&self, db: &SqlitePool) {
sqlx::query!("DELETE FROM boat_reservation WHERE id=?", self.id)
.execute(db)
.await
.unwrap(); //Okay, because we can only create a Boat of a valid id
}
}