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, TripHelpDeleteError, TripUpdateError}, tripdetails::{TripDetails, TripDetailsToAdd}, user::CoxUser, }; #[post("/trip", data = "")] async fn create( db: &State, data: Form>, cox: CoxUser, ) -> Flash { let trip_details_id = TripDetails::create(db, data.into_inner()).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; //TODO: fix //Log::create( // db, // format!( // "Cox {} created trip on {} @ {} for {} rower", // cox.name, trip_details.day, trip_details.planned_starting_time, trip_details.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, always_show: bool, is_locked: bool, } #[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, data.always_show, data.is_locked, ) .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!", ), Err(CoxHelpError::DetailsLocked) => { Flash::error(Redirect::to("/"), "Boot ist bereits eingeteilt.") } } } 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 { match Trip::delete_by_planned_event(db, &cox, &planned_event).await { Ok(_) => { Log::create( db, format!( "Cox {} deleted registration for planned_event.id={}", cox.name, planned_event_id ), ) .await; Flash::success(Redirect::to("/"), "Erfolgreich abgemeldet!") } Err(TripHelpDeleteError::DetailsLocked) => { Flash::error(Redirect::to("/"), "Boot bereits eingeteilt") } Err(TripHelpDeleteError::CoxNotHelping) => { Flash::error(Redirect::to("/"), "Steuermann hilft nicht aus...") } } } 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() ); } #[sqlx::test] fn test_trip_update_succ() { let db = testdb!(); let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0]; assert_eq!(1, trip.trip.max_people); assert_eq!( "trip_details for trip from cox", &trip.trip.notes.clone().unwrap() ); 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/1") .header(ContentType::Form) .body("notes=my-new-notes&max_people=12"); 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 aktualisiert." ); let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0]; assert_eq!(12, trip.trip.max_people); assert_eq!("my-new-notes", &trip.trip.notes.clone().unwrap()); } #[sqlx::test] fn test_trip_update_wrong_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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client .post("/cox/trip/9999") .header(ContentType::Form) .body("notes=my-new-notes&max_people=12"); 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:errorAusfahrt gibt's nicht"); } #[sqlx::test] fn test_trip_update_wrong_cox() { let db = testdb!(); let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0]; assert_eq!(1, trip.trip.max_people); assert_eq!( "trip_details for trip from cox", &trip.trip.notes.clone().unwrap() ); 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=cox2&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client .post("/cox/trip/1") .header(ContentType::Form) .body("notes=my-new-notes&max_people=12"); 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:errorNicht deine Ausfahrt!"); } #[sqlx::test] fn test_trip_join() { 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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/cox/join/1"); 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:successDanke für's helfen!"); let req = client.get("/cox/join/1"); 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:errorDu hilfst bereits aus!"); } #[sqlx::test] fn test_trip_join_already_rower() { 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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/join/1"); let _ = req.dispatch().await; let req = client.get("/cox/join/1"); 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:errorDu hast dich bereits als Ruderer angemeldet!" ); } #[sqlx::test] fn test_trip_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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/cox/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:errorEvent gibt's nicht"); } #[sqlx::test] fn test_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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/cox/join/1"); let response = req.dispatch().await; let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "7:successDanke für's helfen!"); let req = client.get("/cox/join/1"); let _ = req.dispatch().await; let req = client.get("/cox/remove/1"); 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:successErfolgreich abgemeldet!"); } #[sqlx::test] fn test_remove_wrong_id() { 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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/cox/remove/999"); 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:errorPlanned_event does not exist."); } #[sqlx::test] fn test_remove_cox_not_participating() { 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=cox&password=cox"); // Add the form data to the request body; login.dispatch().await; let req = client.get("/cox/remove/1"); 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:errorSteuermann hilft nicht aus..."); } }