diff --git a/src/model/boat.rs b/src/model/boat.rs index 0db76c1..e791c1d 100644 --- a/src/model/boat.rs +++ b/src/model/boat.rs @@ -88,19 +88,37 @@ ORDER BY amount_seats DESC .is_ok() } - // pub async fn update(&self, db: &SqlitePool, is_cox: bool, is_admin: bool, is_guest: bool) { - // sqlx::query!( - // "UPDATE user SET is_cox = ?, is_admin = ?, is_guest = ? where id = ?", - // is_cox, - // is_admin, - // is_guest, - // self.id - // ) - // .execute(db) - // .await - // .unwrap(); //Okay, because we can only create a User of a valid id - // } - // + pub async fn update( + &self, + db: &SqlitePool, + name: &str, + amount_seats: i64, + year_built: Option, + boatbuilder: Option<&str>, + default_shipmaster_only_steering: bool, + skull: bool, + external: bool, + location_id: Option, + owner: Option, + ) -> bool { + sqlx::query!( + "UPDATE boat SET name=?, amount_seats=?, year_built=?, boatbuilder=?, default_shipmaster_only_steering=?, skull=?, external=?, location_id=?, owner=? WHERE id=?", + name, + amount_seats, + year_built, + boatbuilder, + default_shipmaster_only_steering, + skull, + external, + location_id, + owner, + self.id + ) + .execute(db) + .await + .is_ok() + } + pub async fn delete(&self, db: &SqlitePool) { sqlx::query!("DELETE FROM boat WHERE id=?", self.id) .execute(db) @@ -109,124 +127,70 @@ ORDER BY amount_seats DESC } } -//#[cfg(test)] -//mod test { -// use crate::testdb; -// -// use super::User; -// use sqlx::SqlitePool; -// -// #[sqlx::test] -// fn test_find_correct_id() { -// let pool = testdb!(); -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// assert_eq!(user.id, 1); -// } -// -// #[sqlx::test] -// fn test_find_wrong_id() { -// let pool = testdb!(); -// let user = User::find_by_id(&pool, 1337).await; -// assert!(user.is_none()); -// } -// -// #[sqlx::test] -// fn test_find_correct_name() { -// let pool = testdb!(); -// let user = User::find_by_name(&pool, "admin".into()).await.unwrap(); -// assert_eq!(user.id, 1); -// } -// -// #[sqlx::test] -// fn test_find_wrong_name() { -// let pool = testdb!(); -// let user = User::find_by_name(&pool, "name-does-not-exist".into()).await; -// assert!(user.is_none()); -// } -// -// #[sqlx::test] -// fn test_all() { -// let pool = testdb!(); -// let res = User::all(&pool).await; -// assert!(res.len() > 3); -// } -// -// #[sqlx::test] -// fn test_succ_create() { -// let pool = testdb!(); -// -// assert_eq!( -// User::create(&pool, "new-user-name".into(), false).await, -// true -// ); -// } -// -// #[sqlx::test] -// fn test_duplicate_name_create() { -// let pool = testdb!(); -// -// assert_eq!(User::create(&pool, "admin".into(), false).await, false); -// } -// -// #[sqlx::test] -// fn test_update() { -// let pool = testdb!(); -// -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// user.update(&pool, false, false, false).await; -// -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// assert_eq!(user.is_admin, false); -// } -// -// #[sqlx::test] -// fn succ_login_with_test_db() { -// let pool = testdb!(); -// User::login(&pool, "admin".into(), "admin".into()) -// .await -// .unwrap(); -// } -// -// #[sqlx::test] -// fn wrong_pw() { -// let pool = testdb!(); -// assert!(User::login(&pool, "admin".into(), "admi".into()) -// .await -// .is_err()); -// } -// -// #[sqlx::test] -// fn wrong_username() { -// let pool = testdb!(); -// assert!(User::login(&pool, "admi".into(), "admin".into()) -// .await -// .is_err()); -// } -// -// #[sqlx::test] -// fn reset() { -// let pool = testdb!(); -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// -// user.reset_pw(&pool).await; -// -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// assert_eq!(user.pw, None); -// } -// -// #[sqlx::test] -// fn update_pw() { -// let pool = testdb!(); -// let user = User::find_by_id(&pool, 1).await.unwrap(); -// -// assert!(User::login(&pool, "admin".into(), "abc".into()) -// .await -// .is_err()); -// -// user.update_pw(&pool, "abc".into()).await; -// -// User::login(&pool, "admin".into(), "abc".into()) -// .await -// .unwrap(); -// } -//} +#[cfg(test)] +mod test { + use crate::{model::boat::Boat, testdb}; + + use sqlx::SqlitePool; + + #[sqlx::test] + fn test_find_correct_id() { + let pool = testdb!(); + let boat = Boat::find_by_id(&pool, 1).await.unwrap(); + assert_eq!(boat.id, 1); + } + + #[sqlx::test] + fn test_find_wrong_id() { + let pool = testdb!(); + let boat = Boat::find_by_id(&pool, 1337).await; + assert!(boat.is_none()); + } + + #[sqlx::test] + fn test_all() { + let pool = testdb!(); + let res = Boat::all(&pool).await; + assert!(res.len() > 3); + } + + #[sqlx::test] + fn test_succ_create() { + let pool = testdb!(); + + assert_eq!( + Boat::create( + &pool, + "new-boat-name".into(), + 42, + None, + "Best Boatbuilder".into(), + true, + true, + false + ) + .await, + true + ); + } + + #[sqlx::test] + fn test_duplicate_name_create() { + let pool = testdb!(); + + assert_eq!( + Boat::create( + &pool, + "Haichenbach".into(), + 42, + None, + "Best Boatbuilder".into(), + true, + true, + false + ) + .await, + false + ); + } +} diff --git a/src/model/location.rs b/src/model/location.rs new file mode 100644 index 0000000..b0e69c3 --- /dev/null +++ b/src/model/location.rs @@ -0,0 +1,94 @@ +use serde::{Deserialize, Serialize}; +use sqlx::{FromRow, SqlitePool}; + +#[derive(FromRow, Debug, Serialize, Deserialize)] +pub struct Location { + pub id: i64, + pub name: String, +} + +impl Location { + pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option { + sqlx::query_as!( + Self, + " + SELECT id, name + FROM location + WHERE id like ? + ", + id + ) + .fetch_one(db) + .await + .ok() + } + + pub async fn all(db: &SqlitePool) -> Vec { + sqlx::query_as!( + Self, + " +SELECT id, name +FROM location + " + ) + .fetch_all(db) + .await + .unwrap() //TODO: fixme + } + + pub async fn create(db: &SqlitePool, name: &str) -> bool { + sqlx::query!("INSERT INTO location(name) VALUES (?)", name,) + .execute(db) + .await + .is_ok() + } + + pub async fn delete(&self, db: &SqlitePool) { + sqlx::query!("DELETE FROM location WHERE id=?", self.id) + .execute(db) + .await + .unwrap(); //Okay, because we can only create a Location of a valid id + } +} + +#[cfg(test)] +mod test { + use crate::{model::location::Location, testdb}; + + use sqlx::SqlitePool; + + #[sqlx::test] + fn test_find_correct_id() { + let pool = testdb!(); + let location = Location::find_by_id(&pool, 1).await.unwrap(); + assert_eq!(location.id, 1); + } + + #[sqlx::test] + fn test_find_wrong_id() { + let pool = testdb!(); + let location = Location::find_by_id(&pool, 1337).await; + assert!(location.is_none()); + } + + #[sqlx::test] + fn test_all() { + let pool = testdb!(); + let res = Location::all(&pool).await; + assert!(res.len() > 1); + } + + #[sqlx::test] + fn test_succ_create() { + let pool = testdb!(); + + assert_eq!(Location::create(&pool, "new-loc-name".into(),).await, true); + } + + #[sqlx::test] + fn test_duplicate_name_create() { + let pool = testdb!(); + + assert_eq!(Location::create(&pool, "Linz".into(),).await, false); + } +} diff --git a/src/model/mod.rs b/src/model/mod.rs index 6d5c012..9500984 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -8,6 +8,7 @@ use self::{ }; pub mod boat; +pub mod location; pub mod log; pub mod planned_event; pub mod trip; diff --git a/src/tera/admin/boat.rs b/src/tera/admin/boat.rs index c1ccc32..89af9e1 100644 --- a/src/tera/admin/boat.rs +++ b/src/tera/admin/boat.rs @@ -1,4 +1,8 @@ -use crate::model::{boat::Boat, user::AdminUser}; +use crate::model::{ + boat::Boat, + location::Location, + user::{AdminUser, User}, +}; use rocket::{ form::Form, get, post, @@ -16,12 +20,16 @@ async fn index( 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", &admin.user); Template::render("admin/boat/index", context.into_json()) @@ -42,34 +50,58 @@ async fn delete(db: &State, _admin: AdminUser, boat: i32) -> Flash, -// data: Form, -// _admin: AdminUser, -//) -> Flash { -// let user = User::find_by_id(db, data.id).await; -// let Some(user) = user else { -// return Flash::error( -// Redirect::to("/admin/user"), -// format!("User with ID {} does not exist!", data.id), -// ) -// }; -// -// user.update(db, data.is_cox, data.is_admin, data.is_guest) -// .await; -// -// Flash::success(Redirect::to("/admin/user"), "Successfully updated user") -//} -// +#[derive(FromForm)] +struct BoatEditForm<'r> { + id: i32, + name: &'r str, + amount_seats: i64, + year_built: Option, + boatbuilder: Option<&'r str>, + default_shipmaster_only_steering: bool, + skull: bool, + external: bool, + location_id: Option, + owner: Option, +} + +#[post("/boat", data = "")] +async fn update( + db: &State, + data: Form>, + _admin: AdminUser, +) -> Flash { + let boat = Boat::find_by_id(db, data.id).await; + let Some(boat) = boat else { + return Flash::error( + Redirect::to("/admin/boat"), + format!("Boat with ID {} does not exist!", data.id), + ) + }; + + if !boat + .update( + db, + data.name, + data.amount_seats, + data.year_built, + data.boatbuilder, + data.default_shipmaster_only_steering, + data.skull, + data.external, + data.location_id, + data.owner, + ) + .await + { + return Flash::error( + Redirect::to("/admin/boat"), + format!("Boat with ID {} could not be updated!", data.id), + ); + } + + Flash::success(Redirect::to("/admin/boat"), "Successfully updated boat") +} + #[derive(FromForm)] struct BoatAddForm<'r> { name: &'r str, @@ -109,5 +141,5 @@ async fn create( } pub fn routes() -> Vec { - routes![index, create, delete] //, update] + routes![index, create, delete, update] } diff --git a/templates/admin/boat/index.html.tera b/templates/admin/boat/index.html.tera index cdf01c4..1beda21 100644 --- a/templates/admin/boat/index.html.tera +++ b/templates/admin/boat/index.html.tera @@ -59,7 +59,20 @@
-
{{ boat.name }} +
{{ boat.name }}
+
+
+ + + {{ macros::input(label='Name', name='name', type='text', value=boat.name) }} + {{ macros::input(label='Amount Seats', name='amount_seats', type='number', min=0, value=boat.amount_seats) }} + {{ macros::select(data=locations, label='location', select_name='location_id', selected_id=boat.location_id) }} + {{ macros::select(data=users, label='users', select_name='owner', selected_id=boat.owner, default="Vereinsboot") }} + {{ macros::input(label='Baujahr', name='year_built', type='number', min=1950, value=boat.year_built) }} + {{ macros::input(label='Bootsbauer', name='boatbuilder', type='text', value=boat.boatbuilder) }} + {{ macros::checkbox(label='default_shipmaster_only_steering', name='default_shipmaster_only_steering', id=loop.index , checked=boat.default_shipmaster_only_steering) }} + {{ macros::checkbox(label='skull', name='skull', id=loop.index , checked=boat.skull) }} + {{ macros::checkbox(label='external', name='external', id=loop.index , checked=boat.external) }}
diff --git a/templates/forms/event.html.tera b/templates/forms/event.html.tera index 495dc39..6fd0450 100644 --- a/templates/forms/event.html.tera +++ b/templates/forms/event.html.tera @@ -10,7 +10,7 @@ {{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }} {{ macros::checkbox(label='Immer anzeigen', name='always_show') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }} - {{ macros::select(select_name='trip_type', trip_types=trip_types, default='Reguläre Ausfahrt') }} + {{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }} diff --git a/templates/forms/trip.html.tera b/templates/forms/trip.html.tera index 742a792..8b7d0b5 100644 --- a/templates/forms/trip.html.tera +++ b/templates/forms/trip.html.tera @@ -7,7 +7,7 @@ {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='max_people', type='number', required=true, min='0') }} {{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }} - {{ macros::select(select_name='trip_type', trip_types=trip_types, default='Reguläre Ausfahrt') }} + {{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }} diff --git a/templates/includes/macros.html.tera b/templates/includes/macros.html.tera index 951aeaa..9189382 100644 --- a/templates/includes/macros.html.tera +++ b/templates/includes/macros.html.tera @@ -47,11 +47,13 @@ {% endmacro checkbox %} -{% macro select(trip_types, select_name='trip_type', default='', selected_id='') %} +{% macro select(data, select_name='trip_type', default='', selected_id='') %} {% endmacro select %}