use rocket::{ form::Form, get, post, response::{Flash, Redirect}, routes, FromForm, Route, State, }; use sqlx::SqlitePool; use crate::model::{ log::Log, planned_event::PlannedEvent, trip::{CoxHelpError, Trip, TripDeleteError, TripUpdateError}, tripdetails::TripDetails, user::CoxUser, }; #[derive(FromForm)] struct AddTripForm<'r> { day: String, //TODO: properly parse `planned_starting_time` planned_starting_time: &'r str, #[field(validate = range(1..))] max_people: i32, notes: Option<&'r str>, trip_type: Option, allow_guests: bool, } #[post("/trip", data = "")] async fn create( db: &State, data: Form>, cox: CoxUser, ) -> Flash { let trip_details_id = TripDetails::create( db, data.planned_starting_time, data.max_people, &data.day, data.notes, data.allow_guests, data.trip_type, ) .await; let trip_details = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); //Okay, bc just //created Trip::new_own(db, &cox, trip_details).await; Log::create( db, format!( "Cox {} created trip on {} @ {} for {} rower", cox.name, data.day, data.planned_starting_time, data.max_people, ), ) .await; Flash::success(Redirect::to("/"), "Ausfahrt erfolgreich erstellt.") } #[derive(FromForm)] struct EditTripForm<'r> { max_people: i32, notes: Option<&'r str>, trip_type: Option, } #[post("/trip/", data = "")] async fn update( db: &State, data: Form>, trip_id: i64, cox: CoxUser, ) -> Flash { if let Some(trip) = Trip::find_by_id(db, trip_id).await { match Trip::update_own(db, &cox, &trip, data.max_people, data.notes, data.trip_type).await { Ok(_) => Flash::success(Redirect::to("/"), "Ausfahrt erfolgreich aktualisiert."), Err(TripUpdateError::NotYourTrip) => { Flash::error(Redirect::to("/"), "Nicht deine Ausfahrt!") } Err(TripUpdateError::TripDetailsDoesNotExist) => { Flash::error(Redirect::to("/"), "Ausfahrt gibt's nicht") } } } else { Flash::error(Redirect::to("/"), "Ausfahrt gibt's nicht") } } #[get("/join/")] async fn join(db: &State, planned_event_id: i64, cox: CoxUser) -> Flash { if let Some(planned_event) = PlannedEvent::find_by_id(db, planned_event_id).await { match Trip::new_join(db, &cox, &planned_event).await { Ok(_) => { Log::create( db, format!( "Cox {} helps at planned_event.id={}", cox.name, planned_event_id, ), ) .await; Flash::success(Redirect::to("/"), "Danke für's helfen!") } Err(CoxHelpError::AlreadyRegisteredAsCox) => { Flash::error(Redirect::to("/"), "Du hilfst bereits aus!") } Err(CoxHelpError::AlreadyRegisteredAsRower) => Flash::error( Redirect::to("/"), "Du hast dich bereits als Ruderer angemeldet!", ), } } else { Flash::error(Redirect::to("/"), "Event gibt's nicht") } } #[get("/remove/trip/")] async fn remove_trip(db: &State, trip_id: i64, cox: CoxUser) -> Flash { let trip = Trip::find_by_id(db, trip_id).await; match trip { None => Flash::error(Redirect::to("/"), "Trip gibt's nicht!"), Some(trip) => match trip.delete(db, &cox).await { Ok(_) => { Log::create(db, format!("Cox {} deleted trip.id={}", cox.name, trip_id)).await; Flash::success(Redirect::to("/"), "Erfolgreich gelöscht!") } Err(TripDeleteError::SomebodyAlreadyRegistered) => Flash::error( Redirect::to("/"), "Ausfahrt kann nicht gelöscht werden, da bereits jemand registriert ist!", ), Err(TripDeleteError::NotYourTrip) => { Flash::error(Redirect::to("/"), "Nicht deine Ausfahrt!") } }, } } #[get("/remove/")] async fn remove(db: &State, planned_event_id: i64, cox: CoxUser) -> Flash { if let Some(planned_event) = PlannedEvent::find_by_id(db, planned_event_id).await { Trip::delete_by_planned_event(db, &cox, &planned_event).await; Log::create( db, format!( "Cox {} deleted registration for planned_event.id={}", cox.name, planned_event_id ), ) .await; Flash::success(Redirect::to("/"), "Erfolgreich abgemeldet!") } else { Flash::error(Redirect::to("/"), "Planned_event does not exist.") } } pub fn routes() -> Vec { routes![create, join, remove, remove_trip, update] } #[cfg(test)] mod test { use chrono::NaiveDate; use rocket::{ http::{ContentType, Status}, local::asynchronous::Client, }; use sqlx::SqlitePool; use crate::{model::trip::Trip, testdb}; #[sqlx::test] fn test_trip_create() { let db = testdb!(); assert_eq!( 0, Trip::get_for_day(&db, NaiveDate::from_ymd_opt(2999, 12, 30).unwrap()) .await .len() ); 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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client .post("/cox/trip") .header(ContentType::Form) .body("day=2999-12-30&planned_starting_time=12:34&max_people=42&allow_guests=false"); 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(), "7:successAusfahrt erfolgreich erstellt." ); assert_eq!( 1, Trip::get_for_day(&db, NaiveDate::from_ymd_opt(2999, 12, 30).unwrap()) .await .len() ); } }