From 70bbc878598588a77cf28512812d772b8a48a4a4 Mon Sep 17 00:00:00 2001 From: philipp Date: Fri, 29 Sep 2023 12:39:45 +0200 Subject: [PATCH] fun with timezones --- Cargo.lock | 1 + Cargo.toml | 1 + src/model/logbook.rs | 58 +++++++++++++++++--------- src/tera/log.rs | 7 ++-- templates/includes/forms/log.html.tera | 6 +-- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34bbf0a..9607f3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1862,6 +1862,7 @@ version = "0.1.0" dependencies = [ "argon2", "chrono", + "chrono-tz", "env_logger", "futures", "ics", diff --git a/Cargo.toml b/Cargo.toml index 02f1b49..214a762 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ argon2 = "0.5" serde = { version = "1.0", features = [ "derive" ]} serde_json = "1.0" chrono = { version = "0.4", features = ["serde"]} +chrono-tz = "0.8" tera = { version = "1.18", features = ["date-locale"], optional = true} ics = "0.5" futures = "0.3" diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 06cac5c..0d2820e 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -1,4 +1,5 @@ use chrono::{Local, NaiveDateTime, TimeZone}; +use chrono_tz::Europe::Vienna; use rocket::FromForm; use serde::Serialize; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; @@ -56,8 +57,6 @@ pub struct LogbookWithBoatAndRowers { pub boat: Boat, pub shipmaster_user: User, pub rowers: Vec, - pub departure_timestamp: i64, - pub arrival_timestamp: Option, } #[derive(Debug, PartialEq)] @@ -75,6 +74,8 @@ pub enum LogbookDeleteError { #[derive(Debug, PartialEq)] pub enum LogbookCreateError { + ArrivalSetButNoDestination, + ArrivalSetButNoDistance, BoatAlreadyOnWater, BoatLocked, BoatNotFound, @@ -105,7 +106,7 @@ impl Logbook { pub async fn on_water(db: &SqlitePool) -> Vec { let rows = sqlx::query!( " -SELECT id, boat_id, shipmaster, shipmaster_only_steering, strftime('%Y-%m-%d %H:%M', departure) as departure, arrival, destination, distance_in_km, comments, logtype +SELECT id, boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype FROM logbook WHERE arrival is null ORDER BY departure DESC @@ -122,8 +123,7 @@ ORDER BY departure DESC boat_id: row.boat_id, shipmaster: row.shipmaster, shipmaster_only_steering: row.shipmaster_only_steering, - departure: NaiveDateTime::parse_from_str(&row.departure.unwrap(), "%Y-%m-%d %H:%M") - .unwrap(), + departure: row.departure, arrival: row.arrival, destination: row.destination, distance_in_km: row.distance_in_km, @@ -141,8 +141,6 @@ ORDER BY departure DESC boat: Boat::find_by_id(db, log.boat_id as i32).await.unwrap(), shipmaster_user: User::find_by_id(db, log.shipmaster as i32).await.unwrap(), logbook: log, - arrival_timestamp: None, //TODO: send arrival timestmap - departure_timestamp: date_time.timestamp(), }); } ret @@ -169,8 +167,6 @@ ORDER BY departure DESC boat: Boat::find_by_id(db, log.boat_id as i32).await.unwrap(), shipmaster_user: User::find_by_id(db, log.shipmaster as i32).await.unwrap(), logbook: log, - arrival_timestamp: None, - departure_timestamp: 0, }); } ret @@ -197,11 +193,18 @@ ORDER BY departure DESC } if let Some(arrival) = &log.arrival { - let dep = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%d %H:%M").unwrap(); - let arr = NaiveDateTime::parse_from_str(&arrival, "%Y-%m-%d %H:%M").unwrap(); + let dep = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap(); + let arr = NaiveDateTime::parse_from_str(&arrival, "%Y-%m-%dT%H:%M").unwrap(); if arr <= dep { return Err(LogbookCreateError::ArrivalNotAfterDeparture); } + + if log.destination.is_none() { + return Err(LogbookCreateError::ArrivalSetButNoDestination); + } + if log.distance_in_km.is_none() { + return Err(LogbookCreateError::ArrivalSetButNoDistance); + } } if log.rowers.len() > boat.amount_seats as usize - 1 { @@ -222,19 +225,32 @@ ORDER BY departure DESC } } + //let departure = format!("{}+02:00", &log.departure); + let mut tx = db.begin().await.unwrap(); - let departure = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap(); - let arrival = log - .arrival - .map(|a| NaiveDateTime::parse_from_str(&a, "%Y-%m-%dT%H:%M").unwrap()); + //let departure = NaiveDateTime::parse_from_str(&log.departure, "%Y-%m-%dT%H:%M").unwrap(); + //let departure_vienna = chrono::Utc + // .from_local_datetime(&departure) + // .single() + // .unwrap(); + //let departure_utc = departure_vienna.with_timezone(&Vienna); + + //let arrival = log.arrival.map(|a| { + // let arr = NaiveDateTime::parse_from_str(&a, "%Y-%m-%dT%H:%M").unwrap(); + // let arr_vienna = Vienna.from_local_datetime(&arr).single().unwrap(); + // arr_vienna + // .with_timezone(&chrono::Utc) + // .format("%Y-%m-%d %H:%M") + //}); + //let arrival = log.arrival.map(|a| format!("{}+02:00", a)); let inserted_row = sqlx::query!( "INSERT INTO logbook(boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?) RETURNING id", log.boat_id, log.shipmaster, log.shipmaster_only_steering, - departure, - arrival, + log.departure, + log.arrival, log.destination, log.distance_in_km, log.comments, @@ -299,9 +315,11 @@ ORDER BY departure DESC )); } - let arrival = format!("{}", chrono::offset::Local::now().format("%Y-%m-%d %H:%M")); - let chrono_arrival = NaiveDateTime::parse_from_str(&arrival, "%Y-%m-%d %H:%M").unwrap(); - if chrono_arrival <= self.departure { + let arrival = chrono::offset::Utc::now().naive_utc(); + let arrival = Vienna.from_utc_datetime(&arrival); + + if arrival.timestamp() + 60 * 60 * 2 <= self.departure.timestamp() { + //TODO: fixme return Err(LogbookUpdateError::ArrivalNotAfterDeparture); } diff --git a/src/tera/log.rs b/src/tera/log.rs index 6dabec0..81eed91 100644 --- a/src/tera/log.rs +++ b/src/tera/log.rs @@ -159,7 +159,8 @@ async fn create_logbook(db: &SqlitePool, data: Form) -> Flash Flash::error(Redirect::to("/log"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")), Err(LogbookCreateError::RowerCreateError(rower, e)) => Flash::error(Redirect::to("/log"), format!("Fehler bei Ruderer {rower}: {e}")), Err(LogbookCreateError::SamePersonShipmasterAndRower) => Flash::error(Redirect::to("/log"), format!("Selbe Person als Schiffsführer und Ruderer ausgewählt")), - + Err(LogbookCreateError::ArrivalSetButNoDistance) => Flash::error(Redirect::to("/log"), format!("Distanz notwendig, wenn Ankunftszeit angegeben wurde")), + Err(LogbookCreateError::ArrivalSetButNoDestination) => Flash::error(Redirect::to("/log"), format!("Ziel notwendig, wenn Ankunftszeit angegeben wurde")), Err(LogbookCreateError::ArrivalNotAfterDeparture) => Flash::error(Redirect::to("/log"), format!("Ankunftszeit kann nicht vor der Abfahrtszeit sein")), } @@ -200,10 +201,10 @@ async fn home_logbook( match logbook.home(db, user, data.into_inner()).await { Ok(_) => Flash::success(Redirect::to("/log"), "Successfully updated log"), Err(LogbookUpdateError::TooManyRowers(expected, actual)) => Flash::error(Redirect::to("/log"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")), - Err(_) => Flash::error( + Err(a) => {println!("{a:?}"); return Flash::error( Redirect::to("/log"), format!("Logbook with ID {} could not be updated!", logbook_id), - ), + )}, } } diff --git a/templates/includes/forms/log.html.tera b/templates/includes/forms/log.html.tera index 75a5179..4e5db7c 100644 --- a/templates/includes/forms/log.html.tera +++ b/templates/includes/forms/log.html.tera @@ -140,16 +140,16 @@