From 2aa6def5606e42d7aba06eceacc6f2411f36ca5f Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Sat, 3 Jan 2026 21:26:20 +0100 Subject: [PATCH 1/2] be able to show total km of each rower --- src/model/stat.rs | 28 ++++++++++++++++------------ templates/stat.people.html.tera | 15 ++++++++++++--- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/model/stat.rs b/src/model/stat.rs index 2ed663a..c49b36c 100644 --- a/src/model/stat.rs +++ b/src/model/stat.rs @@ -104,9 +104,11 @@ pub struct Stat { impl Stat { pub async fn guest(db: &SqlitePool, year: Option) -> Stat { - let year = match year { - Some(year) => year, - None => chrono::Local::now().year(), + let year = year.unwrap_or_else(|| chrono::Local::now().year()); + let year_filter = if year == 0 { + String::new() + } else { + format!("AND l.arrival LIKE '{}-%'", year) }; //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) // proper guests @@ -121,7 +123,7 @@ LEFT JOIN ( FROM rower GROUP BY logbook_id ) m ON l.id = m.logbook_id -WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' AND not b.external; +WHERE l.distance_in_km IS NOT NULL {year_filter} AND not b.external; " )) .fetch_one(db) @@ -145,7 +147,7 @@ WHERE u.id NOT IN ( WHERE ro.name = 'Donau Linz' ) AND l.distance_in_km IS NOT NULL -AND l.arrival LIKE '{year}-%' +{year_filter} AND u.name != 'Externe Steuerperson'; " )) @@ -183,25 +185,27 @@ AND u.name != 'Externe Steuerperson'; } pub async fn people(db: &SqlitePool, year: Option) -> Vec { - let year = match year { - Some(year) => year, - None => chrono::Local::now().year(), + let year = year.unwrap_or_else(|| chrono::Local::now().year()); + let year_filter = if year == 0 { + String::new() + } else { + format!("AND l.arrival LIKE '{}-%'", year) }; //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) sqlx::query(&format!( " SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km, COUNT(*) AS amount_trips FROM ( - SELECT * FROM user + SELECT * FROM user WHERE id IN ( - SELECT user_id FROM user_role - JOIN role ON user_role.role_id = role.id + SELECT user_id FROM user_role + JOIN role ON user_role.role_id = role.id WHERE role.name = 'Donau Linz' ) ) u INNER JOIN rower r ON u.id = r.rower_id INNER JOIN logbook l ON r.logbook_id = l.id -WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' AND u.name != 'Externe Steuerperson' +WHERE l.distance_in_km IS NOT NULL {year_filter} AND u.name != 'Externe Steuerperson' GROUP BY u.name ORDER BY rowed_km DESC, u.name; " diff --git a/templates/stat.people.html.tera b/templates/stat.people.html.tera index ce947a7..3aaee4b 100644 --- a/templates/stat.people.html.tera +++ b/templates/stat.people.html.tera @@ -78,11 +78,12 @@ var queryParams = new URLSearchParams(window.location.search); return queryParams.get('year'); } - + function populateYears() { var select = document.getElementById('yearSelect'); var currentYear = new Date().getFullYear(); var selectedYear = getYearFromURL() || currentYear; + for (var year = 1977; year <= currentYear; year++) { var option = document.createElement('option'); option.value = option.textContent = year; @@ -91,13 +92,21 @@ } select.appendChild(option); } + + var gesamtOption = document.createElement('option'); + gesamtOption.value = 0; + gesamtOption.textContent = 'GESAMT'; + if (selectedYear == 0) { + gesamtOption.selected = true; + } + select.appendChild(gesamtOption); } - + function changeYear() { var selectedYear = document.getElementById('yearSelect').value; window.location.href = '?year=' + selectedYear; } - + populateYears(); {% endblock content %} -- 2.49.1 From 0ccd59f8a76d22993af335c31fb1885558b45647 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Sat, 3 Jan 2026 22:11:11 +0100 Subject: [PATCH 2/2] force an action on important notifications --- src/model/notification.rs | 16 ++++++++++++++++ src/model/user/mod.rs | 3 +++ templates/base.html.tera | 15 +++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/model/notification.rs b/src/model/notification.rs index cf7b893..253db16 100644 --- a/src/model/notification.rs +++ b/src/model/notification.rs @@ -26,6 +26,22 @@ impl Notification { .await .ok() } + + pub async fn oldest_unread_with_action(db: &SqlitePool, user_id: i64) -> Option { + sqlx::query_as!( + Self, + "SELECT id, user_id, message, read_at, created_at, category, link, action_after_reading + FROM notification + WHERE user_id = ? AND read_at IS NULL AND action_after_reading IS NOT NULL + ORDER BY created_at ASC + LIMIT 1", + user_id + ) + .fetch_optional(db) + .await + .unwrap() + } + pub async fn create_with_tx( db: &mut Transaction<'_, Sqlite>, user: &User, diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index 7c38a31..2cd1fed 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -88,17 +88,20 @@ pub struct UserWithDetails { pub allowed_to_steer: bool, pub on_water: bool, pub roles: Vec, + pub action_notification: Option, } impl UserWithDetails { pub async fn from_user(user: User, db: &SqlitePool) -> Self { let allowed_to_steer = user.allowed_to_steer(db).await; + let action_notification = Notification::oldest_unread_with_action(db, user.id).await; Self { on_water: user.on_water(db).await, roles: user.roles(db).await, amount_unread_notifications: user.amount_unread_notifications(db).await, allowed_to_steer, + action_notification, user, } } diff --git a/templates/base.html.tera b/templates/base.html.tera index f3c4303..79cacce 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -53,6 +53,21 @@ {% include "includes/footer" %} {% endif %} {% include "dynamics/sidebar" %} + {% if loggedin_user and loggedin_user.action_notification %} + +
+ + {{ loggedin_user.action_notification.category }} + +
{{ loggedin_user.action_notification.message }}
+ + ✓ + Notification gelesen + +
+
+ + {% endif %} -- 2.49.1