use crate::model::{ boat::{Boat, BoatToAdd, BoatToUpdate}, location::Location, log::Log, user::{User, UserWithDetails, VorstandUser}, }; use rocket::{ form::Form, get, post, request::FlashMessage, response::{Flash, Redirect}, routes, Route, State, }; use rocket_dyn_templates::{tera::Context, Template}; use sqlx::SqlitePool; #[get("/boat")] async fn index( db: &State, admin: VorstandUser, flash: Option>, ) -> Template { let boats = Boat::all(db).await; let locations = Location::all(db).await; let users = User::all(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("boats", &boats); context.insert("locations", &locations); context.insert("users", &users); context.insert( "loggedin_user", &UserWithDetails::from_user(admin.user, db).await, ); Template::render("admin/boat/index", context.into_json()) } #[get("/boat//delete")] async fn delete(db: &State, admin: VorstandUser, boat: i32) -> Flash { let boat = Boat::find_by_id(db, boat).await; Log::create(db, format!("{} deleted boat: {boat:?}", admin.user.name)).await; match boat { Some(boat) => { boat.delete(db).await; Flash::success( Redirect::to("/admin/boat"), format!("Boot {} gelöscht", boat.name), ) } None => Flash::error(Redirect::to("/admin/boat"), "Boat does not exist"), } } #[post("/boat/", data = "")] async fn update( db: &State, data: Form>, boat_id: i32, _admin: VorstandUser, ) -> Flash { let boat = Boat::find_by_id(db, boat_id).await; let Some(boat) = boat else { return Flash::error(Redirect::to("/admin/boat"), "Boat does not exist!"); }; match boat.update(db, data.into_inner()).await { Ok(_) => Flash::success(Redirect::to("/admin/boat"), "Boot bearbeitet"), Err(e) => Flash::error(Redirect::to("/admin/boat"), e), } } #[post("/boat/new", data = "")] async fn create( db: &State, data: Form>, _admin: VorstandUser, ) -> Flash { match Boat::create(db, data.into_inner()).await { Ok(_) => Flash::success(Redirect::to("/admin/boat"), "Boot hinzugefügt"), Err(e) => Flash::error(Redirect::to("/admin/boat"), e), } } pub fn routes() -> Vec { routes![index, create, delete, update] } #[cfg(test)] mod test { use rocket::{ http::{ContentType, Status}, local::asynchronous::Client, }; use sqlx::SqlitePool; use crate::tera::admin::boat::Boat; use crate::testdb; #[sqlx::test] fn test_boat_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("/admin/boat"); let response = req.dispatch().await; assert_eq!(response.status(), Status::Ok); let text = response.into_string().await.unwrap(); assert!(&text.contains("Neues Boot")); assert!(&text.contains("Kaputtes Boot :-(")); assert!(&text.contains("Haichenbach")); } #[sqlx::test] fn test_succ_update() { let db = testdb!(); let boat = Boat::find_by_id(&db, 1).await.unwrap(); assert_eq!(boat.name, "Haichenbach"); 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("/admin/boat/1") .header(ContentType::Form) .body("name=Haichiii&amount_seats=1&location_id=1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!( response.headers().get("Location").next(), Some("/admin/boat") ); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "7:successBoot bearbeitet"); let boat = Boat::find_by_id(&db, 1).await.unwrap(); assert_eq!(boat.name, "Haichiii"); } #[sqlx::test] fn test_update_wrong_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 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("/admin/boat/1337") .header(ContentType::Form) .body("name=Haichiii&amount_seats=1&location_id=1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!( response.headers().get("Location").next(), Some("/admin/boat") ); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "5:errorBoat does not exist!"); let boat = Boat::find_by_id(&db, 1).await.unwrap(); assert_eq!(boat.name, "Haichenbach"); } #[sqlx::test] fn test_update_wrong_foreign() { 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("/admin/boat/1") .header(ContentType::Form) .body("name=Haichiii&amount_seats=1&location_id=999"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!( response.headers().get("Location").next(), Some("/admin/boat") ); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!( flash_cookie.value(), "5:errorerror returned from database: (code: 787) FOREIGN KEY constraint failed" ); } #[sqlx::test] fn test_succ_create() { let db = testdb!(); let rocket = rocket::build().manage(db.clone()); let rocket = crate::tera::config(rocket); assert!(Boat::find_by_name(&db, "completely-new-boat".into()) .await .is_none()); 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("/admin/boat/new") .header(ContentType::Form) .body("name=completely-new-boat&amount_seats=1&location_id=1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!( response.headers().get("Location").next(), Some("/admin/boat") ); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!(flash_cookie.value(), "7:successBoot hinzugefügt"); Boat::find_by_name(&db, "completely-new-boat".into()) .await .unwrap(); } #[sqlx::test] fn test_create_db_error() { 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("/admin/boat/new") .header(ContentType::Form) .body("name=Haichenbach&amount_seats=1&location_id=1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); assert_eq!( response.headers().get("Location").next(), Some("/admin/boat") ); let flash_cookie = response .cookies() .get("_flash") .expect("Expected flash cookie"); assert_eq!( flash_cookie.value(), "5:errorerror returned from database: (code: 2067) UNIQUE constraint failed: boat.name" ); } }