From 31bf38f11271b8e81a7ed560217929660af69c2f Mon Sep 17 00:00:00 2001 From: philipp Date: Mon, 10 Jun 2024 14:55:01 +0200 Subject: [PATCH] show if a user has < 30 km to thousand km trip, Fixes #551 --- src/model/logbook.rs | 14 +++++++++++--- src/model/stat.rs | 32 ++++++++++++++++++++++++++++++-- src/model/user.rs | 15 ++++++++++++++- src/tera/log.rs | 2 +- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 20585ef..e2d7f05 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -301,7 +301,7 @@ ORDER BY departure DESC db: &SqlitePool, mut log: LogToAdd, created_by_user: &User, - ) -> Result<(), LogbookCreateError> { + ) -> Result { let Some(boat) = Boat::find_by_id(db, log.boat_id).await else { return Err(LogbookCreateError::BoatNotFound); }; @@ -354,7 +354,7 @@ ORDER BY departure DESC { Ok(_) => { tx.commit().await.unwrap(); - Ok(()) + Ok(String::new()) } Err(a) => Err(a.into()), }; @@ -426,7 +426,15 @@ ORDER BY departure DESC tx.commit().await.unwrap(); - Ok(()) + let mut ret = String::new(); + for rower in &log.rowers { + let user = User::find_by_id(db, *rower as i32).await.unwrap(); + if let Some(msg) = user.close_thousands_trip(db).await { + ret.push_str(&format!("\n{msg}")); + } + } + + Ok(ret) } pub async fn distances(db: &SqlitePool) -> Vec<(String, i64)> { diff --git a/src/model/stat.rs b/src/model/stat.rs index 0398115..c27a7dd 100644 --- a/src/model/stat.rs +++ b/src/model/stat.rs @@ -95,7 +95,7 @@ ORDER BY #[derive(FromRow, Serialize, Clone)] pub struct Stat { name: String, - rowed_km: i32, + pub(crate) rowed_km: i32, } impl Stat { @@ -195,6 +195,34 @@ ORDER BY rowed_km DESC, u.name; }) .collect() } + pub async fn person(db: &SqlitePool, year: Option, user: &User) -> Stat { + let year = match year { + Some(year) => year, + None => chrono::Local::now().year(), + }; + //TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server) + let row = sqlx::query(&format!( + " +SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km +FROM ( + SELECT * FROM user + WHERE id={} +) 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}-%'; +", + user.id + )) + .fetch_one(db) + .await + .unwrap(); + + Stat { + name: row.get("name"), + rowed_km: row.get("rowed_km"), + } + } } #[derive(Debug, Serialize)] @@ -218,7 +246,7 @@ FROM ( LEFT JOIN rower r ON l.id = r.logbook_id WHERE - l.shipmaster = {0} OR r.rower_id = {0} + r.rower_id = {} GROUP BY departure_date ) as subquery diff --git a/src/model/user.rs b/src/model/user.rs index 0c184ec..06fb212 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; use super::{ - family::Family, log::Log, mail::Mail, notification::Notification, role::Role, + family::Family, log::Log, mail::Mail, notification::Notification, role::Role, stat::Stat, tripdetails::TripDetails, Day, }; use crate::tera::admin::user::UserEditForm; @@ -849,6 +849,19 @@ ORDER BY last_access DESC 6 } } + + pub(crate) async fn close_thousands_trip(&self, db: &SqlitePool) -> Option { + let rowed_km = Stat::person(db, None, self).await.rowed_km; + if rowed_km % 1000 > 970 { + return Some(format!( + "{} braucht nur mehr {} km bis die {} km voll sind šŸ¤‘", + self.name, + 1000 - rowed_km % 1000, + rowed_km + 1000 - (rowed_km % 1000) + )); + } + None + } } #[async_trait] diff --git a/src/tera/log.rs b/src/tera/log.rs index 8fe3131..7c7ab0c 100644 --- a/src/tera/log.rs +++ b/src/tera/log.rs @@ -212,7 +212,7 @@ async fn create_logbook( ) .await { - Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt erfolgreich hinzugefĆ¼gt"), + Ok(msg) => Flash::success(Redirect::to("/log"), format!("Ausfahrt erfolgreich hinzugefĆ¼gt {msg}")), Err(LogbookCreateError::BoatAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Boot schon am Wasser"), Err(LogbookCreateError::RowerAlreadyOnWater(rower)) => Flash::error(Redirect::to("/log"), format!("Ruderer {} schon am Wasser", rower.name)), Err(LogbookCreateError::BoatLocked) => Flash::error(Redirect::to("/log"),"Boot gesperrt"),