use std::net::IpAddr; use rocket::{ form::Form, get, http::{Cookie, CookieJar}, post, request::{self, FlashMessage, FromRequest}, response::{Flash, Redirect}, routes, time::{Duration, OffsetDateTime}, Request, Route, State, }; use rocket_dyn_templates::{context, Template}; use sqlx::SqlitePool; use tera::Context; use crate::model::{ boat::Boat, log::Log, logbook::{ LogToAdd, LogToFinalize, Logbook, LogbookCreateError, LogbookDeleteError, LogbookUpdateError, }, logtype::LogType, user::{User, UserWithWaterStatus}, }; pub struct KioskCookie(String); #[rocket::async_trait] impl<'r> FromRequest<'r> for KioskCookie { type Error = std::convert::Infallible; async fn from_request(request: &'r Request<'_>) -> request::Outcome { match request.cookies().get_private("kiosk") { Some(cookie) => request::Outcome::Success(KioskCookie(cookie.value().to_string())), None => request::Outcome::Forward(()), } } } #[get("/", rank = 2)] async fn index(db: &State, flash: Option>, user: User) -> Template { let boats = Boat::for_user(db, &user).await; let coxes: Vec = futures::future::join_all( User::cox(db) .await .into_iter() .map(|user| UserWithWaterStatus::from_user(user, db)), ) .await; let users: Vec = futures::future::join_all( User::all(db) .await .into_iter() .map(|user| UserWithWaterStatus::from_user(user, db)), ) .await; let logtypes = LogType::all(db).await; let distances = Logbook::distances(db).await; let on_water = Logbook::on_water(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("boats", &boats); context.insert("coxes", &coxes); context.insert("users", &users); context.insert("logtypes", &logtypes); context.insert("loggedin_user", &user); context.insert("on_water", &on_water); context.insert("distances", &distances); Template::render("log", context.into_json()) } #[get("/show", rank = 2)] async fn show(db: &State, user: User) -> Template { let logs = Logbook::completed(db).await; Template::render("log.completed", context!(logs, loggedin_user: &user)) } #[get("/show")] async fn show_kiosk(db: &State, _kiosk: KioskCookie) -> Template { let logs = Logbook::completed(db).await; Template::render("log.completed", context!(logs, show_kiosk_header: true)) } #[get("/kiosk/ekrv2019/")] async fn new_kiosk( db: &State, cookies: &CookieJar<'_>, loc: String, ip: Option, ) -> Redirect { Log::create( db, format!("New kiosk cookie set for loc '{loc}' (IP={ip:?})"), ) .await; let mut cookie = Cookie::new("kiosk", loc); cookie.set_expires(OffsetDateTime::now_utc() + Duration::weeks(12)); cookies.add_private(cookie); Redirect::to("/log") } #[get("/")] async fn kiosk( db: &State, flash: Option>, kiosk: KioskCookie, ) -> Template { let boats = Boat::all_at_location(db, kiosk.0).await; let coxes: Vec = futures::future::join_all( User::cox(db) .await .into_iter() .map(|user| UserWithWaterStatus::from_user(user, db)), ) .await; let users: Vec = futures::future::join_all( User::all(db) .await .into_iter() .map(|user| UserWithWaterStatus::from_user(user, db)), ) .await; let logtypes = LogType::all(db).await; let distances = Logbook::distances(db).await; let on_water = Logbook::on_water(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("boats", &boats); context.insert("coxes", &coxes); context.insert("users", &users); context.insert("logtypes", &logtypes); context.insert("on_water", &on_water); context.insert("distances", &distances); context.insert("show_kiosk_header", &true); Template::render("kiosk", context.into_json()) } async fn create_logbook(db: &SqlitePool, data: Form, user: &User) -> Flash { return Flash::error(Redirect::to("/log"), "Du musst noch kurz geduldig sein. Sobald wir unser Logbuch umgestellt haben, kannst du es hier im Ruderassistenten verwenden ;)"); match Logbook::create( db, data.into_inner(), user ) .await { Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt erfolgreich hinzugefügt"), Err(LogbookCreateError::BoatAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Boot schon am Wasser"), Err(LogbookCreateError::ShipmasterAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Schiffsführer schon am Wasser"), Err(LogbookCreateError::RowerAlreadyOnWater(rower)) => Flash::error(Redirect::to("/log"), format!("Ruderer {} schon am Wasser", rower.name)), Err(LogbookCreateError::BoatLocked) => Flash::error(Redirect::to("/log"),"Boot gesperrt"), Err(LogbookCreateError::BoatNotFound) => Flash::error(Redirect::to("/log"), "Boot gibt's ned"), Err(LogbookCreateError::TooManyRowers(expected, actual)) => Flash::error(Redirect::to("/log"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")), Err(LogbookCreateError::RowerCreateError(rower, e)) => Flash::error(Redirect::to("/log"), format!("Fehler bei Ruderer {rower}: {e}")), Err(LogbookCreateError::SamePersonShipmasterAndRower) => Flash::error(Redirect::to("/log"), "Selbe Person als Schiffsführer und Ruderer ausgewählt"), Err(LogbookCreateError::ArrivalSetButNoDistance) => Flash::error(Redirect::to("/log"), "Distanz notwendig, wenn Ankunftszeit angegeben wurde"), Err(LogbookCreateError::ArrivalSetButNoDestination) => Flash::error(Redirect::to("/log"), "Ziel notwendig, wenn Ankunftszeit angegeben wurde"), Err(LogbookCreateError::ArrivalNotAfterDeparture) => Flash::error(Redirect::to("/log"), "Ankunftszeit kann nicht vor der Abfahrtszeit sein"), Err(LogbookCreateError::UserNotAllowedToUseBoat) => Flash::error(Redirect::to("/log"), "Schiffsführer darf dieses Boot nicht verwenden"), } } #[post("/", data = "", rank = 2)] async fn create(db: &State, data: Form, user: User) -> Flash { create_logbook(db, data, &user).await } #[post("/", data = "")] async fn create_kiosk( db: &State, data: Form, _kiosk: KioskCookie, ) -> Flash { let creator = User::find_by_id(db, data.shipmaster as i32).await.unwrap(); create_logbook(db, data, &creator).await } async fn home_logbook( db: &SqlitePool, data: Form, logbook_id: i32, user: &User, ) -> Flash { return Flash::error(Redirect::to("/log"), "Du musst noch kurz geduldig sein. Sobald wir unser Logbuch umgestellt haben, kannst du es hier im Ruderassistenten verwenden ;)"); let logbook: Option = Logbook::find_by_id(db, logbook_id).await; let Some(logbook) = logbook else { return Flash::error( Redirect::to("/admin/log"), format!("Log with ID {} does not exist!", logbook_id), ); }; match logbook.home(db, user, data.into_inner()).await { Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt korrekt eingetragen"), Err(LogbookUpdateError::TooManyRowers(expected, actual)) => Flash::error(Redirect::to("/log"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")), Err(_) => Flash::error( Redirect::to("/log"), format!("Eintrag {} konnte nicht abgesendet werden!", logbook_id), ), } } #[post("/", data = "")] async fn home_kiosk( db: &State, data: Form, logbook_id: i32, _kiosk: KioskCookie, ) -> Flash { let logbook = Logbook::find_by_id(db, logbook_id).await.unwrap(); //TODO: fixme home_logbook( db, data, logbook_id, &User::find_by_id(db, logbook.shipmaster as i32) .await .unwrap(), ) .await } #[post("/", data = "", rank = 2)] async fn home( db: &State, data: Form, logbook_id: i32, user: User, ) -> Flash { home_logbook(db, data, logbook_id, &user).await } #[get("//delete", rank = 2)] async fn delete(db: &State, logbook_id: i32, user: User) -> Flash { return Flash::error(Redirect::to("/log"), "Du musst noch kurz geduldig sein. Sobald wir unser Logbuch umgestellt haben, kannst du es hier im Ruderassistenten verwenden ;)"); let logbook = Logbook::find_by_id(db, logbook_id).await; if let Some(logbook) = logbook { match logbook.delete(db, &user).await { Ok(_) => Flash::success( Redirect::to("/log"), format!("Eintrag {} gelöscht!", logbook_id), ), Err(LogbookDeleteError::NotYourEntry) => Flash::error( Redirect::to("/log"), "Du hast nicht die Berechtigung, den Eintrag zu löschen!", ), } } else { Flash::error( Redirect::to("/log"), format!("Logbook with ID {} could not be found!", logbook_id), ) } } #[get("//delete")] async fn delete_kiosk( db: &State, logbook_id: i32, _kiosk: KioskCookie, ) -> Flash { return Flash::error(Redirect::to("/log"), "Du musst noch kurz geduldig sein. Sobald wir unser Logbuch umgestellt haben, kannst du es hier im Ruderassistenten verwenden ;)"); let logbook = Logbook::find_by_id(db, logbook_id).await; if let Some(logbook) = logbook { let cox = User::find_by_id(db, logbook.shipmaster as i32) .await .unwrap(); match logbook.delete(db, &cox).await { Ok(_) => Flash::success( Redirect::to("/log"), format!("Eintrag {} gelöscht!", logbook_id), ), Err(LogbookDeleteError::NotYourEntry) => Flash::error( Redirect::to("/log"), "Du hast nicht die Berechtigung, den Eintrag zu löschen!", ), } } else { Flash::error( Redirect::to("/log"), format!("Logbook with ID {} could not be found!", logbook_id), ) } } pub fn routes() -> Vec { routes![ index, create, create_kiosk, home, kiosk, home_kiosk, new_kiosk, show, show_kiosk, delete, delete_kiosk ] } //#[cfg(test)] //mod test { // use rocket::http::ContentType; // use rocket::{http::Status, local::asynchronous::Client}; // use sqlx::SqlitePool; // // use crate::model::logbook::Logbook; // use crate::tera::{log::Boat, User}; // use crate::testdb; // // #[sqlx::test] // fn test_kiosk_cookie() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/auth")); // // let req = client.get("/log/kiosk/ekrv2019/Linz"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let req = client.get("/log"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::Ok); // let text = response.into_string().await.unwrap(); // assert!(text.contains("Logbuch")); // assert!(text.contains("Neue Ausfahrt")); // // assert!(!text.contains("Ottensheim Boot")); // } // // #[sqlx::test] // fn test_kiosk_cookie_boat() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log/kiosk/ekrv2019/Ottensheim"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let req = client.get("/log"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::Ok); // let text = response.into_string().await.unwrap(); // assert!(text.contains("Logbuch")); // assert!(text.contains("Neue Ausfahrt")); // // assert!(text.contains("Ottensheim Boot")); // } // // #[sqlx::test] // fn test_index() { // 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=admin&password=admin"); // Add the form data to the request body; // login.dispatch().await; // // let req = client.get("/log"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // assert!(text.contains("Logbuch")); // assert!(text.contains("Neue Ausfahrt")); // } // // #[sqlx::test] // fn test_show() { // 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=admin&password=admin"); // Add the form data to the request body; // login.dispatch().await; // // let req = client.get("/log/show"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // println!("{text:?}"); // assert!(text.contains("Logbuch")); // assert!(text.contains("Joe")); // } // // #[sqlx::test] // fn test_show_kiosk() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log/kiosk/ekrv2019/Linz"); // let _ = req.dispatch().await; // // let req = client.get("/log/show"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // assert!(text.contains("Logbuch")); // assert!(text.contains("Joe")); // } // // #[sqlx::test] // fn test_create() { // 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=admin&password=admin"); // Add the form data to the request body; // login.dispatch().await; // // let req = client // .post("/log") // .header(ContentType::Form) // .body("boat_id=1&shipmaster=4&departure=2199-12-31T10:00"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt erfolgreich hinzugefügt" // ); // } // // #[sqlx::test] // fn test_home_kiosk() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log/kiosk/ekrv2019/Linz"); // let _ = req.dispatch().await; // // let req = client // .post("/log/1") // .header(ContentType::Form) // .body("destination=Ottensheim&distance_in_km=25"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt korrekt eingetragen" // ); // } // // //Kiosk mode // // i see all boats // #[sqlx::test] // fn test_kiosks_sees_all_boats() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log/kiosk/ekrv2019/Linz"); // let _ = req.dispatch().await; // // let req = client.get("/log"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // //Sees all boats stationed in Linz // assert!(text.contains("Haichenbach")); // assert!(text.contains("Joe")); // assert!(text.contains("Kaputtes Boot :-(")); // assert!(text.contains("Sehr kaputtes Boot :-((")); // assert!(text.contains("second_private_boat_from_rower")); // assert!(text.contains("private_boat_from_rower")); // // //Doesn't see the one's in Ottensheim // assert!(!text.contains("Ottensheim Boot")); // } // // #[sqlx::test] // fn test_kiosks_can_start_trips_with_all_boats() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // sqlx::query("DELETE FROM logbook;") // .execute(&db) // .await // .unwrap(); // // let mut client = Client::tracked(rocket).await.unwrap(); // let req = client.get("/log/kiosk/ekrv2019/Linz"); // let _ = req.dispatch().await; // // can_start_and_end_trip(&db, &mut client, "Haichenbach".into(), "admin".into()).await; // can_start_and_end_trip(&db, &mut client, "Joe".into(), "admin".into()).await; // can_start_and_end_trip(&db, &mut client, "Kaputtes Boot :-(".into(), "admin".into()).await; // cant_start_trip( // &db, // &mut client, // "Sehr kaputtes Boot :-((".into(), // "admin".into(), // "Boot gesperrt".into(), // ) // .await; // can_start_and_end_trip( // &db, // &mut client, // "second_private_boat_from_rower".into(), // "rower".into(), // ) // .await; // } // // #[sqlx::test] // fn test_shipowner_can_allow_others_to_drive() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // sqlx::query("DELETE FROM logbook;") // .execute(&db) // .await // .unwrap(); // // 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; // // // Owner can start trip: // let boat_id = Boat::find_by_name(&db, "private_boat_from_rower".into()) // .await // .unwrap() // .id; // let shipmaster_id = User::find_by_name(&db, "rower2".into()).await.unwrap().id; // // let req = client.post("/log").header(ContentType::Form).body(format!( // "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00" // )); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt erfolgreich hinzugefügt" // ); // // // Shipmaster can end it // let log_id = Logbook::highest_id(&db).await; // // let login = client // .post("/auth") // .header(ContentType::Form) // Set the content type to form // .body("name=rower2&password=rower"); // Add the form data to the request body; // login.dispatch().await; // // let req = client // .post(format!("/log/{log_id}")) // .header(ContentType::Form) // .body("destination=Ottensheim&distance_in_km=25"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt korrekt eingetragen" // ); // } // // #[sqlx::test] // fn test_normal_user_sees_appropriate_boats() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let mut 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("/log"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // // sqlx::query("DELETE FROM logbook;") // .execute(&db) // .await // .unwrap(); // // //Sees all 1x // assert!(text.contains("Haichenbach")); // can_start_and_end_trip(&db, &mut client, "Haichenbach".into(), "rower".into()).await; // // assert!(text.contains("private_boat_from_rower")); // can_start_and_end_trip( // &db, // &mut client, // "private_boat_from_rower".into(), // "rower".into(), // ) // .await; // // assert!(text.contains("second_private_boat_from_rower")); // can_start_and_end_trip( // &db, // &mut client, // "second_private_boat_from_rower".into(), // "rower".into(), // ) // .await; // // //Don't see anything else // assert!(!text.contains("Joe")); // cant_start_trip( // &db, // &mut client, // "Joe".into(), // "rower".into(), // "Schiffsführer darf dieses Boot nicht verwenden".into(), // ) // .await; // // assert!(!text.contains("Kaputtes Boot :-(")); // cant_start_trip( // &db, // &mut client, // "Kaputtes Boot :-(".into(), // "rower".into(), // "Schiffsführer darf dieses Boot nicht verwenden".into(), // ) // .await; // // assert!(!text.contains("Sehr kaputtes Boot :-((")); // cant_start_trip( // &db, // &mut client, // "Sehr kaputtes Boot :-((".into(), // "rower".into(), // "Boot gesperrt".into(), // ) // .await; // // assert!(!text.contains("Ottensheim Boot")); // cant_start_trip( // &db, // &mut client, // "Ottensheim Boot".into(), // "rower".into(), // "Schiffsführer darf dieses Boot nicht verwenden".into(), // ) // .await; // } // // #[sqlx::test] // fn test_cox_sees_appropriate_boats() { // let db = testdb!(); // // let rocket = rocket::build().manage(db.clone()); // let rocket = crate::tera::config(rocket); // // let mut 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; // // sqlx::query("DELETE FROM logbook;") // .execute(&db) // .await // .unwrap(); // // let req = client.get("/log"); // let response = req.dispatch().await; // // let text = response.into_string().await.unwrap(); // // //Sees all 1x // assert!(text.contains("Haichenbach")); // can_start_and_end_trip(&db, &mut client, "Haichenbach".into(), "cox".into()).await; // // assert!(text.contains("Joe")); // can_start_and_end_trip(&db, &mut client, "Joe".into(), "cox".into()).await; // // assert!(text.contains("Kaputtes Boot :-(")); // can_start_and_end_trip(&db, &mut client, "Kaputtes Boot :-(".into(), "cox".into()).await; // // assert!(text.contains("Sehr kaputtes Boot :-((")); // cant_start_trip( // &db, // &mut client, // "Sehr kaputtes Boot :-((".into(), // "cox".into(), // "Boot gesperrt".into(), // ) // .await; // // assert!(text.contains("Ottensheim Boot")); // can_start_and_end_trip(&db, &mut client, "Ottensheim Boot".into(), "cox".into()).await; // // //Can't use private boats // assert!(!text.contains("private_boat_from_rower")); // cant_start_trip( // &db, // &mut client, // "private_boat_from_rower".into(), // "cox".into(), // "Schiffsführer darf dieses Boot nicht verwenden".into(), // ) // .await; // // assert!(!text.contains("second_private_boat_from_rower")); // cant_start_trip( // &db, // &mut client, // "second_private_boat_from_rower".into(), // "cox".into(), // "Schiffsführer darf dieses Boot nicht verwenden".into(), // ) // .await; // } // // #[sqlx::test] // fn test_cant_end_trip_other_user() { // 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=rower2&password=rower"); // Add the form data to the request body; // login.dispatch().await; // // let req = client // .post("/log/1") // .header(ContentType::Form) // .body("destination=Ottensheim&distance_in_km=25"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "5:errorEintrag 1 konnte nicht abgesendet werden!" // ); // } // // async fn can_start_and_end_trip( // db: &SqlitePool, // client: &mut Client, // boat_name: String, // shipmaster_name: String, // ) { // let boat_id = Boat::find_by_name(db, boat_name).await.unwrap().id; // let shipmaster_id = User::find_by_name(db, &shipmaster_name).await.unwrap().id; // // let req = client.post("/log").header(ContentType::Form).body(format!( // "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00" // )); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt erfolgreich hinzugefügt" // ); // // let log_id = Logbook::highest_id(db).await; // // let req = client // .post(format!("/log/{log_id}")) // .header(ContentType::Form) // .body("destination=Ottensheim&distance_in_km=25"); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!( // flash_cookie.value(), // "7:successAusfahrt korrekt eingetragen" // ); // } // // async fn cant_start_trip( // db: &SqlitePool, // client: &mut Client, // boat_name: String, // shipmaster_name: String, // reason: String, // ) { // let boat_id = Boat::find_by_name(db, boat_name).await.unwrap().id; // let shipmaster_id = User::find_by_name(db, &shipmaster_name).await.unwrap().id; // // let req = client.post("/log").header(ContentType::Form).body(format!( // "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=2199-12-31T10:00" // )); // let response = req.dispatch().await; // // assert_eq!(response.status(), Status::SeeOther); // assert_eq!(response.headers().get("Location").next(), Some("/log")); // // let flash_cookie = response // .cookies() // .get("_flash") // .expect("Expected flash cookie"); // // assert_eq!(flash_cookie.value(), format!("5:error{}", reason)); // } //}