diff --git a/seeds.sql b/seeds.sql index 00652ed..e825338 100644 --- a/seeds.sql +++ b/seeds.sql @@ -23,6 +23,7 @@ INSERT INTO "boat" (name, amount_seats, location_id) VALUES ('Joe', 2, 1); INSERT INTO "boat" (name, amount_seats, location_id) VALUES ('Kaputtes Boot :-(', 7, 1); INSERT INTO "boat" (name, amount_seats, location_id) VALUES ('Sehr kaputtes Boot :-((', 7, 1); INSERT INTO "boat" (name, amount_seats, location_id) VALUES ('Ottensheim Boot', 7, 2); +INSERT INTO "boat" (name, amount_seats, location_id, owner) VALUES ('second_private_boat_from_rower', 1, 1, 2); INSERT INTO "logbook_type" (name) VALUES ('Wanderfahrt'); INSERT INTO "logbook_type" (name) VALUES ('Regatta'); INSERT INTO "logbook" (boat_id, shipmaster, shipmaster_only_steering, departure) VALUES (2, 2, false, '1142-12-24 10:00'); diff --git a/src/model/boat.rs b/src/model/boat.rs index baf21f7..244bc7f 100644 --- a/src/model/boat.rs +++ b/src/model/boat.rs @@ -136,7 +136,9 @@ ORDER BY amount_seats DESC if user.is_admin { return Self::all(db).await; } - let boats = sqlx::query_as!( + let mut boats; + if user.is_cox { + boats = sqlx::query_as!( Boat, " SELECT id, name, amount_seats, location_id, owner, year_built, boatbuilder, default_shipmaster_only_steering, skull, external @@ -149,6 +151,21 @@ ORDER BY amount_seats DESC .fetch_all(db) .await .unwrap(); //TODO: fixme + } else { + boats = sqlx::query_as!( + Boat, + " +SELECT id, name, amount_seats, location_id, owner, year_built, boatbuilder, default_shipmaster_only_steering, skull, external +FROM boat +WHERE owner = ? OR (owner is null and amount_seats = 1) +ORDER BY amount_seats DESC + ", + user.id + ) + .fetch_all(db) + .await + .unwrap(); //TODO: fixme + } Self::boats_to_details(db, boats).await } diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 8c33a96..377cf36 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -294,6 +294,16 @@ ORDER BY departure DESC .unwrap(); } + #[cfg(test)] + pub async fn highest_id(db: &SqlitePool) -> i32 { + sqlx::query!("SELECT max(id) as id FROM logbook") + .fetch_one(db) + .await + .unwrap() + .id + .unwrap() + } + pub async fn home( &self, db: &SqlitePool, diff --git a/src/tera/log.rs b/src/tera/log.rs index 81eed91..acf3e31 100644 --- a/src/tera/log.rs +++ b/src/tera/log.rs @@ -38,12 +38,8 @@ impl<'r> FromRequest<'r> for KioskCookie { } #[get("/", rank = 2)] -async fn index( - db: &State, - flash: Option>, - adminuser: AdminUser, -) -> Template { - let boats = Boat::for_user(db, &adminuser.user).await; +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) @@ -73,7 +69,7 @@ async fn index( context.insert("coxes", &coxes); context.insert("users", &users); context.insert("logtypes", &logtypes); - context.insert("loggedin_user", &adminuser.user); + context.insert("loggedin_user", &user); context.insert("on_water", &on_water); context.insert("distances", &distances); @@ -232,9 +228,9 @@ async fn home( db: &State, data: Form, logbook_id: i32, - adminuser: AdminUser, + user: User, ) -> Flash { - home_logbook(db, data, logbook_id, &adminuser.user).await + home_logbook(db, data, logbook_id, &user).await } #[get("//delete")] @@ -280,6 +276,8 @@ mod test { 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] @@ -463,4 +461,177 @@ mod test { assert_eq!(flash_cookie.value(), "7:successSuccessfully updated log"); } + + //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); + + 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(), + "admin".into(), + ) + .await; + } + + #[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 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(); + + //Sees all 1x + assert!(text.contains("Haichenbach")); + assert!(text.contains("private_boat_from_rower")); + assert!(text.contains("second_private_boat_from_rower")); + + //Don't see anything else + assert!(!text.contains("Joe")); + assert!(!text.contains("Kaputtes Boot :-(")); + assert!(!text.contains("Sehr kaputtes Boot :-((")); + assert!(!text.contains("Ottensheim Boot")); + } + + async fn can_start_and_end_trip( + db: &SqlitePool, + client: &mut Client, + boat_name: String, + shipmaster_name: String, + ) { + println!("{boat_name}"); + 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"); + + println!("{shipmaster_id}"); + 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:successSuccessfully updated log"); + + //TODO: Remove the following query? + //sqlx::query(&format!( + // "DELETE FROM logbook WHERE boat_id={boat_id} AND shipmaster={shipmaster_id}" + //)) + //.execute(db) + //.await + //.unwrap(); + } + + 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)); + } }