diff --git a/frontend/tests/log.spec.ts b/frontend/tests/log.spec.ts index f0d8f7a..7692ed1 100644 --- a/frontend/tests/log.spec.ts +++ b/frontend/tests/log.spec.ts @@ -81,7 +81,7 @@ test("Cox can start and finish trip", async ({ page }, testInfo) => { const currentValue = await page.$eval(datetimeSelector, el => el.value); const currentDate = new Date(currentValue); currentDate.setMinutes(currentDate.getMinutes() + 1); - currentDate.setHours(currentDate.getHours() + 1); + currentDate.setHours(currentDate.getHours() - new Date().getTimezoneOffset()/60); const newDatetime = currentDate.toISOString().slice(0, 16); await page.$eval(datetimeSelector, (el, value) => el.value = value, newDatetime); @@ -165,7 +165,7 @@ test("Kiosk can start and finish trip", async ({ page }, testInfo) => { const currentValue = await page.$eval(datetimeSelector, el => el.value); const currentDate = new Date(currentValue); currentDate.setMinutes(currentDate.getMinutes() + 1); - currentDate.setHours(currentDate.getHours() + 1); + currentDate.setHours(currentDate.getHours() - new Date().getTimezoneOffset()/60); const newDatetime = currentDate.toISOString().slice(0, 16); await page.$eval(datetimeSelector, (el, value) => el.value = value, newDatetime); diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 36fcd9c..d853b3f 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -5,7 +5,9 @@ use rocket::FromForm; use serde::Serialize; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; -use super::{boat::Boat, log::Log, notification::Notification, rower::Rower, user::User}; +use super::{ + boat::Boat, log::Log, notification::Notification, role::Role, rower::Rower, user::User, +}; #[derive(FromRow, Serialize, Clone, Debug)] pub struct Logbook { @@ -505,7 +507,7 @@ ORDER BY departure DESC let dep = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap(); let arr = NaiveDateTime::parse_from_str(&log.arrival, "%Y-%m-%dT%H:%M").unwrap(); - if arr.timestamp() <= dep.timestamp() { + if arr.timestamp() < dep.timestamp() { return Err(LogbookUpdateError::ArrivalNotAfterDeparture); } let today = Local::now().date_naive(); @@ -560,6 +562,31 @@ ORDER BY departure DESC .execute(db.deref_mut()) .await.unwrap(); //TODO: fixme + let duration = arr - dep; + if duration.num_days() > 0 { + let vorstand = Role::find_by_name_tx(db, "Vorstand").await.unwrap(); + + Notification::create_for_role_tx( + db, + &vorstand, + &format!("'{}' hat eine mehrtägige Ausfahrt vom {} bis {} eingetragen ({} km; Ziel: {}; Anmerkungen: {}). Falls das nicht stimmen sollte, bitte nachhaken.",user.name,log.departure, log.arrival, log.distance_in_km, log.destination, log.comments.clone().unwrap_or("".into())), + "Mehrtägige Ausfahrt eingetragen", + None, + ).await; + } + + if boat.name == "Externes Boot" { + let vorstand = Role::find_by_name_tx(db, "Vorstand").await.unwrap(); + + Notification::create_for_role_tx( + db, + &vorstand, + &format!("'{}' hat eine Ausfahrt mit *Externem Boot* am {} eingetragen ({} km; Ziel: {}; Anmerkungen: {}). Falls das nicht stimmen sollte, bitte nachhaken.",user.name,log.departure,log.distance_in_km, log.destination, log.comments.unwrap_or("".into())), + "Ausfahrt mit externem Boot eingetragen", + None, + ).await; + } + Ok(()) } diff --git a/src/model/notification.rs b/src/model/notification.rs index 2ec3923..4678eb4 100644 --- a/src/model/notification.rs +++ b/src/model/notification.rs @@ -4,7 +4,7 @@ use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; -use super::user::User; +use super::{role::Role, user::User}; #[derive(FromRow, Debug, Serialize, Deserialize)] pub struct Notification { @@ -55,6 +55,20 @@ impl Notification { tx.commit().await.unwrap(); } + pub async fn create_for_role_tx( + db: &mut Transaction<'_, Sqlite>, + role: &Role, + message: &str, + category: &str, + link: Option<&str>, + ) { + let users = User::all_with_role_tx(db, role).await; + + for user in users { + Self::create_with_tx(db, &user, message, category, link).await; + } + } + pub async fn for_user(db: &SqlitePool, user: &User) -> Vec { sqlx::query_as!( Self, diff --git a/src/model/role.rs b/src/model/role.rs index c1a51ee..8904860 100644 --- a/src/model/role.rs +++ b/src/model/role.rs @@ -1,5 +1,7 @@ +use std::ops::DerefMut; + use serde::Serialize; -use sqlx::{FromRow, SqlitePool}; +use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; #[derive(FromRow, Serialize, Clone)] pub struct Role { @@ -45,6 +47,21 @@ WHERE name like ? .ok() } + pub async fn find_by_name_tx(db: &mut Transaction<'_, Sqlite>, name: &str) -> Option { + sqlx::query_as!( + Self, + " +SELECT id, name +FROM role +WHERE name like ? + ", + name + ) + .fetch_one(db.deref_mut()) + .await + .ok() + } + pub async fn names_from_role(&self, db: &SqlitePool) -> Vec { let query = format!( "SELECT u.name diff --git a/src/model/user.rs b/src/model/user.rs index e1dbd15..86e311a 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -370,6 +370,13 @@ ORDER BY last_access DESC } pub async fn all_with_role(db: &SqlitePool, role: &Role) -> Vec { + let mut tx = db.begin().await.unwrap(); + let ret = Self::all_with_role_tx(&mut tx, role).await; + tx.commit().await.unwrap(); + ret + } + + pub async fn all_with_role_tx(db: &mut Transaction<'_, Sqlite>, role: &Role) -> Vec { sqlx::query_as!( Self, " @@ -380,7 +387,7 @@ WHERE ur.role_id = ? AND deleted = 0 ORDER BY name; ", role.id ) - .fetch_all(db) + .fetch_all(db.deref_mut()) .await .unwrap() } diff --git a/templates/includes/forms/log.html.tera b/templates/includes/forms/log.html.tera index d79b824..67bb2a9 100644 --- a/templates/includes/forms/log.html.tera +++ b/templates/includes/forms/log.html.tera @@ -222,56 +222,58 @@
Ruderer: {% for rower in log.rowers -%} - {{ rower.name -}} - {% if not loop.last or amount_guests > 0 and log.boat.name != 'Externes Boot' %},{% endif %} - {% endfor %} - {% if amount_guests > 0 and log.boat.name != 'Externes Boot' %} - Gäste - (ohne Account): - {{ amount_guests }} - {% endif %} -
+ {{ rower.name }} + {%- if rower.id == log.steering_user.id and rower.id != log.shipmaster_user.id %} + (Steuerperson){%- endif -%} + {%- if not loop.last or amount_guests > 0 and log.boat.name != 'Externes Boot' %},{% endif %} + {% endfor -%} + {% if amount_guests > 0 and log.boat.name != 'Externes Boot' %} + Gäste + (ohne Account): + {{ amount_guests }} + {% endif %} + + {% endif %} {% endif %} {% endif %} - {% endif %} - - -{% endmacro show_old %} -{% macro home(log) %} -
- {{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local', required=true, class="change-id-js rounded-md current-date-time") }} -
- - -
-
- {{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km" ~ log.id , type="number", min=0, value=log.distance_in_km, required=true, class="rounded-md change-id-js") }} - km -
- {{ macros::input(label="Kommentar", name="comments", id="comments" ~ log.id, type="text", value=log.comments, class="rounded-md change-id-js") }} -
- Details ändern -
- {{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true, class="change-id-js rounded-md", value=log.departure) }} - {{ log::rower_select(id="rowers"~log.id, selected=log.rowers, amount_seats=log.boat.amount_seats, steering_person_id=log.steering_user.id, cox_on_boat=log.shipmaster_user.id) }} - {{ macros::select(label="Schiffsführer", data=[], name='shipmaster', id="shipmaster-rowers"~log.id, class="change-id-js", selected_id=log.shipmaster_user.id, required=true) }} - {{ macros::select(label="Steuerperson", data=[], name='steering_person', id="steering_person-rowers"~log.id, class="change-id-js", selected_id=log.steering_user.id, required=true) }} -
- {{ macros::checkbox(label="Handgesteuert", name="shipmaster_only_steering", id="shipmaster_only_steering" ~ log.id , checked=log.shipmaster_only_steering,class="rounded-md change-id-js") }} -
- {{ macros::select(label="Typ", data=logtypes, name="logtype", id="logtype" ~ log.id, default="Normal", selected_id=log.logtype, class="rounded-md change-id-js") }}
-
- -
-{% endmacro home %} + + {% endmacro show_old %} + {% macro home(log) %} +
+ {{ macros::input(label='Ankunftszeit', name='arrival', type='datetime-local', required=true, class="change-id-js rounded-md current-date-time") }} +
+ + +
+
+ {{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km" ~ log.id , type="number", min=0, value=log.distance_in_km, required=true, class="rounded-md change-id-js") }} + km +
+ {{ macros::input(label="Kommentar", name="comments", id="comments" ~ log.id, type="text", value=log.comments, class="rounded-md change-id-js") }} +
+ Details ändern +
+ {{ macros::input(label='Abfahrtszeit', name='departure', type='datetime-local', required=true, class="change-id-js rounded-md", value=log.departure) }} + {{ log::rower_select(id="rowers"~log.id, selected=log.rowers, amount_seats=log.boat.amount_seats, steering_person_id=log.steering_user.id, cox_on_boat=log.shipmaster_user.id) }} + {{ macros::select(label="Schiffsführer", data=[], name='shipmaster', id="shipmaster-rowers"~log.id, class="change-id-js", selected_id=log.shipmaster_user.id, required=true) }} + {{ macros::select(label="Steuerperson", data=[], name='steering_person', id="steering_person-rowers"~log.id, class="change-id-js", selected_id=log.steering_user.id, required=true) }} +
+ {{ macros::checkbox(label="Handgesteuert", name="shipmaster_only_steering", id="shipmaster_only_steering" ~ log.id , checked=log.shipmaster_only_steering,class="rounded-md change-id-js") }} +
+ {{ macros::select(label="Typ", data=logtypes, name="logtype", id="logtype" ~ log.id, default="Normal", selected_id=log.logtype, class="rounded-md change-id-js") }} +
+
+ +
+ {% endmacro home %}