use chrono::NaiveDate; use rocket::{ form::Form, get, post, request::FlashMessage, response::{Flash, Redirect}, routes, FromForm, Route, State, }; use rocket_dyn_templates::Template; use sqlx::SqlitePool; use tera::Context; use crate::{ model::{ boat::Boat, boatreservation::{BoatReservation, BoatReservationToAdd}, log::Log, user::{DonauLinzUser, User, UserWithRolesAndNotificationCount}, }, tera::log::KioskCookie, }; #[get("/")] async fn index_kiosk( db: &State, flash: Option>, _kiosk: KioskCookie, ) -> Template { let boatreservations = BoatReservation::all_future(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } let linz_boats = Boat::all_for_boatshouse(db).await; let mut boats = Vec::new(); for boat in linz_boats { if boat.boat.owner.is_none() { boats.push(boat); } } context.insert("boatreservations", &boatreservations); context.insert("boats", &boats); context.insert("user", &User::all(db).await); context.insert("show_kiosk_header", &true); Template::render("boatreservations", context.into_json()) } #[get("/", rank = 2)] async fn index( db: &State, flash: Option>, user: DonauLinzUser, ) -> Template { let boatreservations = BoatReservation::all_future(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } let linz_boats = Boat::all_for_boatshouse(db).await; let mut boats = Vec::new(); for boat in linz_boats { if boat.boat.owner.is_none() { boats.push(boat); } } context.insert("boatreservations", &boatreservations); context.insert("boats", &boats); context.insert("user", &User::all(db).await); context.insert( "loggedin_user", &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, ); Template::render("boatreservations", context.into_json()) } #[derive(Debug, FromForm)] pub struct FormBoatReservationToAdd<'r> { pub boat_id: i64, pub start_date: &'r str, pub end_date: &'r str, pub time_desc: &'r str, pub usage: &'r str, pub user_id_applicant: Option, } #[post("/new", data = "", rank = 2)] async fn create<'r>( db: &State, data: Form>, user: DonauLinzUser, ) -> Flash { let user_applicant: User = user.into(); let boat = Boat::find_by_id(db, data.boat_id as i32).await.unwrap(); let boatreservation_to_add = BoatReservationToAdd { boat: &boat, start_date: NaiveDate::parse_from_str(data.start_date, "%Y-%m-%d").unwrap(), end_date: NaiveDate::parse_from_str(data.end_date, "%Y-%m-%d").unwrap(), time_desc: data.time_desc, usage: data.usage, user_applicant: &user_applicant, }; match BoatReservation::create(db, boatreservation_to_add).await { Ok(_) => Flash::success( Redirect::to("/boatreservation"), "Reservierung erfolgreich hinzugefügt", ), Err(e) => Flash::error(Redirect::to("/boatreservation"), format!("Fehler: {e}")), } } #[post("/new", data = "")] async fn create_from_kiosk<'r>( db: &State, data: Form>, _kiosk: KioskCookie, ) -> Flash { let user_applicant: User = User::find_by_id(db, data.user_id_applicant.unwrap() as i32) .await .unwrap(); let boat = Boat::find_by_id(db, data.boat_id as i32).await.unwrap(); let boatreservation_to_add = BoatReservationToAdd { boat: &boat, start_date: NaiveDate::parse_from_str(data.start_date, "%Y-%m-%d").unwrap(), end_date: NaiveDate::parse_from_str(data.end_date, "%Y-%m-%d").unwrap(), time_desc: data.time_desc, usage: data.usage, user_applicant: &user_applicant, }; match BoatReservation::create(db, boatreservation_to_add).await { Ok(_) => Flash::success( Redirect::to("/boatreservation"), "Reservierung erfolgreich hinzugefügt", ), Err(e) => Flash::error(Redirect::to("/boatreservation"), format!("Fehler: {e}")), } } #[derive(FromForm, Debug)] pub struct ReservationEditForm { pub(crate) id: i32, pub(crate) time_desc: String, pub(crate) usage: String, } #[post("/", data = "")] async fn update( db: &State, data: Form, user: User, ) -> Flash { let Some(reservation) = BoatReservation::find_by_id(db, data.id).await else { return Flash::error( Redirect::to("/boatreservation"), format!("Reservation with ID {} does not exist!", data.id), ); }; if user.id != reservation.user_id_applicant && !user.has_role(db, "admin").await { return Flash::error( Redirect::to("/boatreservation"), format!("Not allowed to update reservation (only admins + creator do so)."), ); } Log::create( db, format!( "{} updated reservation from {reservation:?} to {data:?}", user.name ), ) .await; reservation.update(db, data.into_inner()).await; Flash::success( Redirect::to("/boatreservation"), "Reservierung erfolgreich bearbeitet", ) } #[get("//delete")] async fn delete<'r>( db: &State, reservation_id: i32, user: DonauLinzUser, ) -> Flash { let reservation = BoatReservation::find_by_id(db, reservation_id) .await .unwrap(); if user.id == reservation.user_id_applicant || user.has_role(db, "admin").await { reservation.delete(db).await; Flash::success( Redirect::to("/boatreservation"), "Reservierung erfolgreich gelöscht", ) } else { Flash::error( Redirect::to("/boatreservation"), "Nur der Reservierer darf die Reservierung löschen.".to_string(), ) } } pub fn routes() -> Vec { routes![ index, index_kiosk, create, create_from_kiosk, delete, update ] }