verify, that boat is not on water on adding log entry; Fixes #625 #696

Merged
philipp merged 10 commits from boat-water-check into staging 2024-08-21 17:05:38 +02:00
3 changed files with 43 additions and 0 deletions
Showing only changes of commit 6a581aac64 - Show all commits

View File

@ -1,5 +1,6 @@
use std::ops::DerefMut; use std::ops::DerefMut;
use chrono::NaiveDateTime;
use itertools::Itertools; use itertools::Itertools;
use rocket::serde::{Deserialize, Serialize}; use rocket::serde::{Deserialize, Serialize};
use rocket::FromForm; use rocket::FromForm;
@ -391,6 +392,39 @@ ORDER BY amount_seats DESC
.await .await
.ok() .ok()
} }
pub async fn on_water_between(
&self,
db: &mut Transaction<'_, Sqlite>,
dep: NaiveDateTime,
arr: NaiveDateTime,
) -> bool {
let dep = dep.format("%Y-%m-%dT%H:%M").to_string();
let arr = arr.format("%Y-%m-%dT%H:%M").to_string();
sqlx::query!(
"SELECT COUNT(*) AS overlap_count
FROM logbook
WHERE boat_id = ?
AND (
(departure <= ? AND arrival >= ?) -- Existing entry covers the entire new period
OR (departure >= ? AND departure < ?) -- Existing entry starts during the new period
OR (arrival > ? AND arrival <= ?) -- Existing entry ends during the new period
);",
self.id,
arr,
arr,
dep,
dep,
dep,
arr
)
.fetch_one(db.deref_mut())
.await
.unwrap()
.overlap_count
> 0
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -142,6 +142,7 @@ pub enum LogbookUpdateError {
TooFast(i64, i64), TooFast(i64, i64),
AlreadyFinalized, AlreadyFinalized,
ExternalSteeringPersonMustSteerOrShipmaster, ExternalSteeringPersonMustSteerOrShipmaster,
BoatAlreadyOnWater,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -196,6 +197,7 @@ impl From<LogbookUpdateError> for LogbookCreateError {
LogbookUpdateError::ExternalSteeringPersonMustSteerOrShipmaster => { LogbookUpdateError::ExternalSteeringPersonMustSteerOrShipmaster => {
LogbookCreateError::ExternalSteeringPersonMustSteerOrShipmaster LogbookCreateError::ExternalSteeringPersonMustSteerOrShipmaster
} }
LogbookUpdateError::BoatAlreadyOnWater => LogbookCreateError::BoatAlreadyOnWater,
} }
} }
} }
@ -573,6 +575,12 @@ ORDER BY departure DESC
return Err(LogbookUpdateError::ArrivalNotAfterDeparture); return Err(LogbookUpdateError::ArrivalNotAfterDeparture);
} }
if !boat.external {
if boat.on_water_between(db, dep, arr).await {
return Err(LogbookUpdateError::BoatAlreadyOnWater);
};
}
let duration_in_mins = (arr.and_utc().timestamp() - dep.and_utc().timestamp()) / 60; let duration_in_mins = (arr.and_utc().timestamp() - dep.and_utc().timestamp()) / 60;
// Not possible to row < 1 min / 500 m = < 2 min / km // Not possible to row < 1 min / 500 m = < 2 min / km
let possible_distance_km = duration_in_mins / 2; let possible_distance_km = duration_in_mins / 2;

View File

@ -347,6 +347,7 @@ async fn home_logbook(
Err(LogbookUpdateError::TooFast(km, min)) => Flash::error(Redirect::to("/log"), format!("KM zu groß für die eingegebene Dauer ({km} km in {min} Minuten). Bitte überprüfe deine Start- und Endzeit und versuche es erneut.")), Err(LogbookUpdateError::TooFast(km, min)) => Flash::error(Redirect::to("/log"), format!("KM zu groß für die eingegebene Dauer ({km} km in {min} Minuten). Bitte überprüfe deine Start- und Endzeit und versuche es erneut.")),
Err(LogbookUpdateError::AlreadyFinalized) => Flash::error(Redirect::to("/log"), "Logbucheintrag wurde bereits abgeschlossen."), Err(LogbookUpdateError::AlreadyFinalized) => Flash::error(Redirect::to("/log"), "Logbucheintrag wurde bereits abgeschlossen."),
Err(LogbookUpdateError::ExternalSteeringPersonMustSteerOrShipmaster) => Flash::error(Redirect::to("/log"), "Wenn du eine 'Externe Steuerperson' hinzufügst, muss diese steuern oder Schiffsführer sein!"), Err(LogbookUpdateError::ExternalSteeringPersonMustSteerOrShipmaster) => Flash::error(Redirect::to("/log"), "Wenn du eine 'Externe Steuerperson' hinzufügst, muss diese steuern oder Schiffsführer sein!"),
Err(LogbookUpdateError::BoatAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Das Boot war in diesem Zeitraum schon am Wasser. Bitte überprüfe das Datum und die Zeit."),
Err(e) => Flash::error( Err(e) => Flash::error(
Redirect::to("/log"), Redirect::to("/log"),
format!("Eintrag {logbook_id} konnte nicht abgesendet werden (Fehler: {e:?})!"), format!("Eintrag {logbook_id} konnte nicht abgesendet werden (Fehler: {e:?})!"),