use rocket::{ get, request::FlashMessage, response::{Flash, Redirect}, routes, Route, State, }; use rocket_dyn_templates::Template; use sqlx::SqlitePool; use tera::Context; use crate::model::{ log::Log, logbook::Logbook, tripdetails::TripDetails, triptype::TripType, user::{AllowedForPlannedTripsUser, User, UserWithRoles}, usertrip::{UserTrip, UserTripDeleteError, UserTripError}, }; #[get("/")] async fn index( db: &State, user: AllowedForPlannedTripsUser, flash: Option>, ) -> Template { let user: User = user.into(); let mut context = Context::new(); if user.has_role(db, "cox").await || user.has_role(db, "planned_event").await { let triptypes = TripType::all(db).await; context.insert("trip_types", &triptypes); } if user.has_role(db, "scheckbuch").await { let last_trips = Logbook::completed_with_user(db, &user).await; context.insert("last_trips", &last_trips); } let days = user.get_days(db).await; if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("fee", &user.fee(db).await); context.insert("loggedin_user", &UserWithRoles::from_user(user, db).await); context.insert("days", &days); Template::render("planned", context.into_json()) } #[get("/join/?")] async fn join( db: &State, trip_details_id: i64, user: AllowedForPlannedTripsUser, user_note: Option, ) -> Flash { let user: User = user.into(); let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else { return Flash::error(Redirect::to("/"), "Trip_details do not exist."); }; match UserTrip::create(db, &user, &trip_details, user_note).await { Ok(registered_user) => { if registered_user == user.name { Log::create( db, format!( "User {} registered for trip_details.id={}", user.name, trip_details_id ), ) .await; }else{ Log::create( db, format!( "User {} registered the guest '{}' for trip_details.id={}", user.name, registered_user, trip_details_id ), ).await; } Flash::success(Redirect::to("/planned"), "Erfolgreich angemeldet!") } Err(UserTripError::EventAlreadyFull) => { Flash::error(Redirect::to("/planned"), "Event bereits ausgebucht!") } Err(UserTripError::AlreadyRegistered) => { Flash::error(Redirect::to("/planned"), "Du nimmst bereits teil!") } Err(UserTripError::AlreadyRegisteredAsCox) => { Flash::error(Redirect::to("/planned"), "Du hilfst bereits als Steuerperson aus!") } Err(UserTripError::CantRegisterAtOwnEvent) => Flash::error( Redirect::to("/planned"), "Du kannst bei einer selbst ausgeschriebenen Fahrt nicht mitrudern ;)", ), Err(UserTripError::GuestNotAllowedForThisEvent) => Flash::error( Redirect::to("/planned"), "Bei dieser Ausfahrt können leider keine Gäste mitfahren.", ), Err(UserTripError::NotAllowedToAddGuest) => Flash::error( Redirect::to("/planned"), "Du darfst keine Gäste hinzufügen.", ), Err(UserTripError::DetailsLocked) => Flash::error( Redirect::to("/planned"), "Die Boote sind bereits zugeteilt. Bitte wende dich an die zuständige Person oder einen der angemeldeten Steuerleute (siehe Nummern in der Signalgruppe), wenn du nachfragen möchtest, ob doch noch Plätze verfügbar sind.", ), } } #[get("/remove//")] async fn remove_guest( db: &State, trip_details_id: i64, user: AllowedForPlannedTripsUser, name: String, ) -> Flash { let user: User = user.into(); let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else { return Flash::error(Redirect::to("/planned"), "TripDetailsId does not exist"); }; match UserTrip::delete(db, &user, &trip_details, Some(name)).await { Ok(_) => { Log::create( db, format!( "User {} unregistered for trip_details.id={}", user.name, trip_details_id ), ) .await; Flash::success(Redirect::to("/planned"), "Erfolgreich abgemeldet!") } Err(UserTripDeleteError::DetailsLocked) => { Log::create( db, format!( "User {} tried to unregister for locked trip_details.id={}", user.name, trip_details_id ), ) .await; Flash::error(Redirect::to("/planned"), "Das Boot ist bereits eingeteilt. Bitte kontaktiere den Schiffsführer (Nummern siehe Signalgruppe) falls du dich doch abmelden willst.") } Err(UserTripDeleteError::GuestNotParticipating) => { Flash::error(Redirect::to("/planned"), "Gast nicht angemeldet.") } Err(UserTripDeleteError::NotAllowedToDeleteGuest) => Flash::error( Redirect::to("/planned"), "Keine Berechtigung um den Gast zu entfernen.", ), } } #[get("/remove/")] async fn remove( db: &State, trip_details_id: i64, user: AllowedForPlannedTripsUser, ) -> Flash { let user: User = user.into(); let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else { return Flash::error(Redirect::to("/planned"), "TripDetailsId does not exist"); }; match UserTrip::delete(db, &user, &trip_details, None).await { Ok(_) => { Log::create( db, format!( "User {} unregistered for trip_details.id={}", user.name, trip_details_id ), ) .await; Flash::success(Redirect::to("/planned"), "Erfolgreich abgemeldet!") } Err(UserTripDeleteError::DetailsLocked) => { Log::create( db, format!( "User {} tried to unregister for locked trip_details.id={}", user.name, trip_details_id ), ) .await; Flash::error(Redirect::to("/planned"), "Das Boot ist bereits eingeteilt. Bitte kontaktiere den Schiffsführer (Nummern siehe Signalgruppe) falls du dich doch abmelden willst.") } Err(_) => { panic!("Not possible to be here"); } } } pub fn routes() -> Vec { routes![index, join, remove, remove_guest] } #[cfg(test)] mod test { use rocket::{ http::{ContentType, Status}, local::asynchronous::Client, }; use sqlx::SqlitePool; use crate::testdb; #[sqlx::test] fn test_join_and_remove() { let db = testdb!(); let rocket = rocket::build().manage(db.clone()); let rocket = crate::tera::config(rocket); let client = Client::tracked(rocket).await.unwrap(); let login = client .post("/auth") .header(ContentType::Form) // Set the content type to form .body("name=rower&password=rower"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/planned/join/1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.headers().get("Location").next(), Some("/planned")); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "7:successErfolgreich angemeldet!"); let req = client.get("/planned/remove/1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.headers().get("Location").next(), Some("/planned")); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "7:successErfolgreich abgemeldet!"); } #[sqlx::test] fn test_join_invalid_event() { let db = testdb!(); let rocket = rocket::build().manage(db.clone()); let rocket = crate::tera::config(rocket); let client = Client::tracked(rocket).await.unwrap(); let login = client .post("/auth") .header(ContentType::Form) // Set the content type to form .body("name=rower&password=rower"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/planned/join/9999"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.headers().get("Location").next(), Some("/")); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "5:errorTrip_details do not exist."); } }