2023-10-29 20:41:30 +01:00
use chrono ::NaiveDateTime ;
2023-07-25 13:22:11 +02:00
use rocket ::FromForm ;
2023-07-24 13:01:39 +02:00
use serde ::Serialize ;
2023-07-25 13:22:11 +02:00
use sqlx ::{ FromRow , Sqlite , SqlitePool , Transaction } ;
2023-07-23 12:17:57 +02:00
2023-10-05 08:59:13 +02:00
use super ::{ boat ::Boat , log ::Log , rower ::Rower , user ::User } ;
2023-07-23 16:49:14 +02:00
2023-07-31 19:10:34 +02:00
#[ derive(FromRow, Serialize, Clone, Debug) ]
2023-07-23 12:17:57 +02:00
pub struct Logbook {
pub id : i64 ,
pub boat_id : i64 ,
pub shipmaster : i64 ,
2023-10-29 18:42:12 +01:00
pub steering_person : i64 ,
2023-07-23 12:17:57 +02:00
#[ serde(default = " bool::default " ) ]
pub shipmaster_only_steering : bool ,
2023-08-05 16:27:51 +02:00
pub departure : NaiveDateTime ,
pub arrival : Option < NaiveDateTime > ,
2023-07-23 12:17:57 +02:00
pub destination : Option < String > ,
pub distance_in_km : Option < i64 > ,
pub comments : Option < String > ,
pub logtype : Option < i64 > ,
}
2023-07-31 19:10:34 +02:00
impl PartialEq for Logbook {
fn eq ( & self , other : & Self ) -> bool {
self . id = = other . id
}
}
2023-10-29 20:41:30 +01:00
#[ derive(FromForm, Debug, Clone) ]
2023-07-25 13:22:11 +02:00
pub struct LogToAdd {
pub boat_id : i32 ,
pub shipmaster : i64 ,
2023-10-29 18:42:12 +01:00
pub steering_person : i64 ,
2023-07-25 13:22:11 +02:00
pub shipmaster_only_steering : bool ,
pub departure : String ,
pub arrival : Option < String > ,
pub destination : Option < String > ,
pub distance_in_km : Option < i64 > ,
pub comments : Option < String > ,
pub logtype : Option < i64 > ,
2023-09-23 18:12:48 +02:00
pub rowers : Vec < i64 > ,
2023-07-25 13:22:11 +02:00
}
2023-10-01 15:53:45 +02:00
#[ derive(FromForm, Debug) ]
2023-07-25 13:22:11 +02:00
pub struct LogToFinalize {
2023-10-29 18:42:12 +01:00
pub shipmaster : i64 ,
pub steering_person : i64 ,
pub shipmaster_only_steering : bool ,
pub departure : String ,
pub arrival : String ,
2023-07-25 13:22:11 +02:00
pub destination : String ,
pub distance_in_km : i64 ,
pub comments : Option < String > ,
pub logtype : Option < i64 > ,
2023-09-23 18:26:04 +02:00
pub rowers : Vec < i64 > ,
2023-07-25 13:22:11 +02:00
}
2023-10-29 20:41:30 +01:00
impl TryFrom < LogToAdd > for LogToFinalize {
type Error = String ;
fn try_from ( value : LogToAdd ) -> Result < Self , Self ::Error > {
if let ( Some ( arrival ) , Some ( destination ) , Some ( distance_in_km ) ) =
( value . arrival , value . destination , value . distance_in_km )
{
return Ok ( LogToFinalize {
arrival ,
destination ,
distance_in_km ,
shipmaster : value . shipmaster ,
steering_person : value . steering_person ,
shipmaster_only_steering : value . shipmaster_only_steering ,
departure : value . departure ,
comments : value . comments ,
logtype : value . logtype ,
rowers : value . rowers ,
} ) ;
}
Err ( " Arrival, destination or distance_in_km not set " . into ( ) )
}
}
2023-09-23 18:12:48 +02:00
#[ derive(Serialize, Debug) ]
2023-07-24 13:01:39 +02:00
pub struct LogbookWithBoatAndRowers {
#[ serde(flatten) ]
pub logbook : Logbook ,
pub boat : Boat ,
pub shipmaster_user : User ,
2023-10-29 18:42:12 +01:00
pub steering_user : User ,
2023-07-24 13:01:39 +02:00
pub rowers : Vec < User > ,
2023-07-23 12:17:57 +02:00
}
2023-07-31 19:10:34 +02:00
#[ derive(Debug, PartialEq) ]
2023-07-23 16:49:14 +02:00
pub enum LogbookUpdateError {
NotYourEntry ,
2023-07-24 20:56:46 +02:00
TooManyRowers ( usize , usize ) ,
2023-07-31 16:59:15 +02:00
RowerCreateError ( i64 , String ) ,
2023-09-24 09:48:01 +02:00
ArrivalNotAfterDeparture ,
2023-10-29 20:41:30 +01:00
ShipmasterNotInRowers ,
SteeringPersonNotInRowers ,
UserNotAllowedToUseBoat ,
2023-07-23 16:49:14 +02:00
}
2023-09-24 09:55:51 +02:00
#[ derive(Debug, PartialEq) ]
pub enum LogbookDeleteError {
NotYourEntry ,
}
2023-07-31 19:10:34 +02:00
#[ derive(Debug, PartialEq) ]
2023-07-23 16:49:14 +02:00
pub enum LogbookCreateError {
2023-10-01 15:53:45 +02:00
UserNotAllowedToUseBoat ,
2023-07-23 16:49:14 +02:00
BoatAlreadyOnWater ,
2023-07-23 19:45:48 +02:00
BoatLocked ,
2023-07-24 13:01:39 +02:00
BoatNotFound ,
TooManyRowers ( usize , usize ) ,
2023-07-27 15:24:29 +02:00
RowerAlreadyOnWater ( User ) ,
2023-07-31 16:59:15 +02:00
RowerCreateError ( i64 , String ) ,
2023-09-24 09:48:01 +02:00
ArrivalNotAfterDeparture ,
2023-10-29 20:41:30 +01:00
SteeringPersonNotInRowers ,
ShipmasterNotInRowers ,
NotYourEntry ,
ArrivalSetButNotRemainingTwo ,
}
impl From < LogbookUpdateError > for LogbookCreateError {
fn from ( value : LogbookUpdateError ) -> Self {
return match value {
LogbookUpdateError ::NotYourEntry = > LogbookCreateError ::NotYourEntry ,
LogbookUpdateError ::TooManyRowers ( a , b ) = > LogbookCreateError ::TooManyRowers ( a , b ) ,
LogbookUpdateError ::RowerCreateError ( a , b ) = > {
LogbookCreateError ::RowerCreateError ( a , b )
}
LogbookUpdateError ::ArrivalNotAfterDeparture = > {
LogbookCreateError ::ArrivalNotAfterDeparture
}
LogbookUpdateError ::ShipmasterNotInRowers = > LogbookCreateError ::ShipmasterNotInRowers ,
LogbookUpdateError ::SteeringPersonNotInRowers = > {
LogbookCreateError ::SteeringPersonNotInRowers
}
LogbookUpdateError ::UserNotAllowedToUseBoat = > {
LogbookCreateError ::UserNotAllowedToUseBoat
}
} ;
}
2023-07-23 16:49:14 +02:00
}
2023-07-23 12:17:57 +02:00
impl Logbook {
2023-07-23 16:49:14 +02:00
pub async fn find_by_id ( db : & SqlitePool , id : i32 ) -> Option < Self > {
sqlx ::query_as! (
Self ,
"
2023-10-29 18:42:12 +01:00
SELECT id , boat_id , shipmaster , steering_person , shipmaster_only_steering , departure , arrival , destination , distance_in_km , comments , logtype
2023-07-23 16:49:14 +02:00
FROM logbook
WHERE id like ?
" ,
id
)
. fetch_one ( db )
. await
. ok ( )
}
2023-07-24 13:01:39 +02:00
pub async fn on_water ( db : & SqlitePool ) -> Vec < LogbookWithBoatAndRowers > {
2023-07-30 22:17:47 +02:00
let rows = sqlx ::query! (
"
2023-10-29 20:41:30 +01:00
SELECT id , boat_id , shipmaster , steering_person , shipmaster_only_steering , departure , arrival , destination , distance_in_km , comments , logtype
2023-07-30 22:17:47 +02:00
FROM logbook
WHERE arrival is null
ORDER BY departure DESC
"
)
. fetch_all ( db )
. await
. unwrap ( ) ; //TODO: fixme
let logs : Vec < Logbook > = rows
. into_iter ( )
. map ( | row | Logbook {
id : row . id ,
boat_id : row . boat_id ,
shipmaster : row . shipmaster ,
2023-10-29 18:42:12 +01:00
steering_person : row . steering_person ,
2023-07-30 22:17:47 +02:00
shipmaster_only_steering : row . shipmaster_only_steering ,
2023-09-29 12:39:45 +02:00
departure : row . departure ,
2023-07-30 22:17:47 +02:00
arrival : row . arrival ,
destination : row . destination ,
distance_in_km : row . distance_in_km ,
comments : row . comments ,
logtype : row . logtype ,
} )
. collect ( ) ;
2023-07-24 13:01:39 +02:00
let mut ret = Vec ::new ( ) ;
for log in logs {
ret . push ( LogbookWithBoatAndRowers {
rowers : Rower ::for_log ( db , & log ) . await ,
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 ( ) ,
2023-10-29 18:42:12 +01:00
steering_user : User ::find_by_id ( db , log . steering_person as i32 )
. await
. unwrap ( ) ,
2023-07-24 13:01:39 +02:00
logbook : log ,
2023-07-25 13:32:20 +02:00
} ) ;
2023-07-24 13:01:39 +02:00
}
ret
2023-07-23 12:17:57 +02:00
}
2023-07-24 13:01:39 +02:00
pub async fn completed ( db : & SqlitePool ) -> Vec < LogbookWithBoatAndRowers > {
let logs = sqlx ::query_as! (
Logbook ,
2023-07-23 12:17:57 +02:00
"
2023-10-29 18:42:12 +01:00
SELECT id , boat_id , shipmaster , steering_person , shipmaster_only_steering , departure , arrival , destination , distance_in_km , comments , logtype
2023-07-23 12:17:57 +02:00
FROM logbook
WHERE arrival is not null
2023-07-24 13:01:39 +02:00
ORDER BY departure DESC
2023-07-23 12:17:57 +02:00
"
)
. fetch_all ( db )
. await
2023-07-24 13:01:39 +02:00
. unwrap ( ) ; //TODO: fixme
let mut ret = Vec ::new ( ) ;
for log in logs {
ret . push ( LogbookWithBoatAndRowers {
rowers : Rower ::for_log ( db , & log ) . await ,
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 ( ) ,
2023-10-29 18:42:12 +01:00
steering_user : User ::find_by_id ( db , log . steering_person as i32 )
. await
. unwrap ( ) ,
2023-07-24 13:01:39 +02:00
logbook : log ,
2023-07-25 13:32:20 +02:00
} ) ;
2023-07-24 13:01:39 +02:00
}
ret
2023-07-23 12:17:57 +02:00
}
2023-10-01 15:53:45 +02:00
pub async fn create (
db : & SqlitePool ,
log : LogToAdd ,
created_by_user : & User ,
) -> Result < ( ) , LogbookCreateError > {
2023-07-25 13:32:20 +02:00
let Some ( boat ) = Boat ::find_by_id ( db , log . boat_id ) . await else {
2023-07-31 16:59:15 +02:00
return Err ( LogbookCreateError ::BoatNotFound ) ;
} ;
2023-07-24 13:01:39 +02:00
2023-10-31 20:57:05 +01:00
if let Ok ( log_to_finalize ) = TryInto ::< LogToFinalize > ::try_into ( log . clone ( ) ) {
//TODO: fix clone() above
if ! boat . shipmaster_allowed ( created_by_user ) . await {
return Err ( LogbookCreateError ::UserNotAllowedToUseBoat ) ;
}
let mut tx = db . begin ( ) . await . unwrap ( ) ;
let inserted_row = sqlx ::query! (
" INSERT INTO logbook(boat_id, shipmaster, steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?,?) RETURNING id " ,
log . boat_id ,
log . shipmaster ,
log . steering_person ,
log . shipmaster_only_steering ,
log . departure ,
log . arrival ,
log . destination ,
log . distance_in_km ,
log . comments ,
log . logtype
)
. fetch_one ( & mut tx )
. await . unwrap ( ) . id ;
let logbook = Logbook ::find_by_id ( db , inserted_row as i32 ) . await . unwrap ( ) ; //ok
return match logbook
. home_with_transaction ( & mut tx , created_by_user , log_to_finalize )
. await
{
Ok ( _ ) = > {
tx . commit ( ) . await . unwrap ( ) ;
Ok ( ( ) )
}
Err ( a ) = > Err ( a . into ( ) ) ,
} ;
}
if log . arrival . is_some ( ) {
return Err ( LogbookCreateError ::ArrivalSetButNotRemainingTwo ) ;
}
2023-07-24 13:01:39 +02:00
if boat . is_locked ( db ) . await {
return Err ( LogbookCreateError ::BoatLocked ) ;
}
if boat . on_water ( db ) . await {
return Err ( LogbookCreateError ::BoatAlreadyOnWater ) ;
}
2023-09-24 09:48:01 +02:00
2023-10-29 20:41:30 +01:00
if ! log . rowers . contains ( & log . shipmaster ) {
return Err ( LogbookCreateError ::ShipmasterNotInRowers ) ;
2023-07-27 15:00:52 +02:00
}
2023-10-29 20:41:30 +01:00
if ! log . rowers . contains ( & log . steering_person ) {
return Err ( LogbookCreateError ::SteeringPersonNotInRowers ) ;
2023-09-24 09:48:01 +02:00
}
2023-10-29 20:41:30 +01:00
if log . rowers . len ( ) > boat . amount_seats as usize {
2023-07-24 13:01:39 +02:00
return Err ( LogbookCreateError ::TooManyRowers (
boat . amount_seats as usize ,
2023-10-29 20:41:30 +01:00
log . rowers . len ( ) ,
2023-07-24 13:01:39 +02:00
) ) ;
}
2023-09-23 18:12:48 +02:00
for rower in & log . rowers {
2023-07-27 15:24:29 +02:00
let user = User ::find_by_id ( db , * rower as i32 ) . await . unwrap ( ) ;
2023-09-24 09:12:27 +02:00
2023-07-27 15:24:29 +02:00
if user . on_water ( db ) . await {
return Err ( LogbookCreateError ::RowerAlreadyOnWater ( user ) ) ;
}
}
2023-10-01 15:53:45 +02:00
if ! boat . shipmaster_allowed ( created_by_user ) . await {
return Err ( LogbookCreateError ::UserNotAllowedToUseBoat ) ;
}
2023-09-29 12:39:45 +02:00
//let departure = format!("{}+02:00", &log.departure);
2023-10-05 08:59:13 +02:00
Log ::create ( db , format! ( " New trip started: {log:?} " ) ) . await ;
2023-09-29 12:39:45 +02:00
2023-07-25 13:22:11 +02:00
let mut tx = db . begin ( ) . await . unwrap ( ) ;
2023-07-24 13:01:39 +02:00
let inserted_row = sqlx ::query! (
2023-10-29 18:42:12 +01:00
" INSERT INTO logbook(boat_id, shipmaster, steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?,?) RETURNING id " ,
2023-07-25 13:22:11 +02:00
log . boat_id ,
log . shipmaster ,
2023-10-29 18:42:12 +01:00
log . steering_person ,
2023-07-25 13:22:11 +02:00
log . shipmaster_only_steering ,
2023-09-29 12:39:45 +02:00
log . departure ,
log . arrival ,
2023-07-25 13:22:11 +02:00
log . destination ,
log . distance_in_km ,
log . comments ,
log . logtype
2023-07-23 12:17:57 +02:00
)
2023-07-25 13:22:11 +02:00
. fetch_one ( & mut tx )
2023-07-24 13:01:39 +02:00
. await . unwrap ( ) ;
2023-09-23 18:12:48 +02:00
for rower in & log . rowers {
2023-07-31 16:59:15 +02:00
Rower ::create ( & mut tx , inserted_row . id , * rower )
. await
2023-09-06 14:39:36 +02:00
. map_err ( | e | LogbookCreateError ::RowerCreateError ( * rower , e . to_string ( ) ) ) ? ;
2023-07-24 13:01:39 +02:00
}
2023-07-25 13:22:11 +02:00
tx . commit ( ) . await . unwrap ( ) ;
2023-07-23 16:49:14 +02:00
Ok ( ( ) )
2023-07-23 12:17:57 +02:00
}
2023-07-23 16:49:14 +02:00
2023-07-30 20:40:15 +02:00
pub async fn distances ( db : & SqlitePool ) -> Vec < ( String , i64 ) > {
2023-07-26 12:56:19 +02:00
let result = sqlx ::query! ( " SELECT destination, distance_in_km FROM logbook WHERE id IN (SELECT MIN(id) FROM logbook GROUP BY destination) AND destination IS NOT NULL AND distance_in_km IS NOT NULL; " )
. fetch_all ( db )
. await
. unwrap ( ) ;
2023-07-30 20:40:15 +02:00
result
. into_iter ( )
. filter_map ( | r | {
if let ( Some ( destination ) , Some ( distance_in_km ) ) = ( r . destination , r . distance_in_km )
{
Some ( ( destination , distance_in_km ) )
} else {
None
}
} )
. collect ( )
2023-07-26 12:56:19 +02:00
}
2023-07-25 13:22:11 +02:00
async fn remove_rowers ( & self , db : & mut Transaction < '_ , Sqlite > ) {
2023-07-24 20:56:46 +02:00
sqlx ::query! ( " DELETE FROM rower WHERE logbook_id=? " , self . id )
. execute ( db )
. await
. unwrap ( ) ;
}
2023-10-01 13:48:21 +02:00
#[ cfg(test) ]
pub async fn highest_id ( db : & SqlitePool ) -> i32 {
sqlx ::query! ( " SELECT max(id) as id FROM logbook " )
. fetch_one ( db )
. await
. unwrap ( )
. id
. unwrap ( )
}
2023-07-23 16:49:14 +02:00
pub async fn home (
& self ,
db : & SqlitePool ,
user : & User ,
2023-07-25 13:22:11 +02:00
log : LogToFinalize ,
2023-07-23 16:49:14 +02:00
) -> Result < ( ) , LogbookUpdateError > {
2023-10-29 20:41:30 +01:00
let mut tx = db . begin ( ) . await . unwrap ( ) ;
self . home_with_transaction ( & mut tx , user , log ) . await ? ;
tx . commit ( ) . await . unwrap ( ) ;
Ok ( ( ) )
}
async fn home_with_transaction (
& self ,
db : & mut Transaction < '_ , Sqlite > ,
user : & User ,
log : LogToFinalize ,
) -> Result < ( ) , LogbookUpdateError > {
//TODO: extract common tests with `create()`
2023-07-23 16:49:14 +02:00
if user . id ! = self . shipmaster {
return Err ( LogbookUpdateError ::NotYourEntry ) ;
}
2023-07-24 20:56:46 +02:00
2023-10-29 20:41:30 +01:00
if ! log . rowers . contains ( & log . shipmaster ) {
return Err ( LogbookUpdateError ::ShipmasterNotInRowers ) ;
}
if ! log . rowers . contains ( & log . steering_person ) {
return Err ( LogbookUpdateError ::SteeringPersonNotInRowers ) ;
}
2023-07-24 20:56:46 +02:00
2023-10-29 20:41:30 +01:00
let boat = Boat ::find_by_id_tx ( db , self . boat_id as i32 ) . await . unwrap ( ) ; //ok
if ! boat . shipmaster_allowed ( & user ) . await & & self . shipmaster ! = user . id {
//second part:
//shipmaster has
//entered a
//different user,
//then the user
//should be able
//to `home` it
return Err ( LogbookUpdateError ::UserNotAllowedToUseBoat ) ;
}
if log . rowers . len ( ) > boat . amount_seats as usize {
2023-07-24 20:56:46 +02:00
return Err ( LogbookUpdateError ::TooManyRowers (
boat . amount_seats as usize ,
2023-10-29 20:41:30 +01:00
log . rowers . len ( ) ,
2023-07-24 20:56:46 +02:00
) ) ;
}
2023-10-29 20:41:30 +01:00
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 ( ) {
2023-09-24 09:48:01 +02:00
return Err ( LogbookUpdateError ::ArrivalNotAfterDeparture ) ;
}
2023-07-23 16:49:14 +02:00
2023-10-29 20:41:30 +01:00
Log ::create_with_tx ( db , format! ( " New trip: {log:?} " ) ) . await ;
self . remove_rowers ( db ) . await ;
for rower in & log . rowers {
Rower ::create ( db , self . id , * rower )
. await
. map_err ( | e | LogbookUpdateError ::RowerCreateError ( * rower , e . to_string ( ) ) ) ? ;
}
2023-07-25 13:22:11 +02:00
2023-07-23 16:49:14 +02:00
sqlx ::query! (
2023-10-29 20:41:30 +01:00
" UPDATE logbook SET shipmaster=?, steering_person=?, shipmaster_only_steering=?, departure=?, destination=?, distance_in_km=?, comments=?, logtype=?, arrival=? WHERE id=? " ,
log . shipmaster ,
log . steering_person ,
log . shipmaster_only_steering ,
log . departure ,
2023-07-25 13:22:11 +02:00
log . destination ,
log . distance_in_km ,
log . comments ,
log . logtype ,
2023-10-29 20:41:30 +01:00
log . arrival ,
2023-07-23 16:49:14 +02:00
self . id
)
2023-10-29 20:41:30 +01:00
. execute ( db )
2023-07-23 16:49:14 +02:00
. await . unwrap ( ) ; //TODO: fixme
2023-07-24 20:56:46 +02:00
2023-07-23 16:49:14 +02:00
Ok ( ( ) )
}
2023-09-24 09:55:51 +02:00
pub async fn delete ( & self , db : & SqlitePool , user : & User ) -> Result < ( ) , LogbookDeleteError > {
2023-10-05 08:59:13 +02:00
Log ::create ( db , format! ( " {user:?} deleted trip: {self:?} " ) ) . await ;
2023-09-24 09:55:51 +02:00
if user . is_admin | | user . id = = self . shipmaster {
sqlx ::query! ( " DELETE FROM logbook WHERE id=? " , self . id )
. execute ( db )
. await
. unwrap ( ) ; //Okay, because we can only create a Logbook of a valid id
return Ok ( ( ) ) ;
}
Err ( LogbookDeleteError ::NotYourEntry )
2023-08-05 16:27:51 +02:00
}
2023-07-23 12:17:57 +02:00
}
2023-07-31 19:10:34 +02:00
#[ cfg(test) ]
mod test {
use super ::{ LogToAdd , Logbook , LogbookCreateError , LogbookUpdateError } ;
use crate ::model ::user ::User ;
use crate ::testdb ;
use sqlx ::SqlitePool ;
#[ sqlx::test ]
fn test_find_correct_id ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
assert_eq! ( logbook . id , 1 ) ;
}
#[ sqlx::test ]
fn test_find_wrong_id ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1337 ) . await ;
assert_eq! ( logbook , None ) ;
}
#[ sqlx::test ]
fn test_on_water ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
2023-07-31 20:09:03 +02:00
let logbook_with_details = Logbook ::on_water ( & pool ) . await ;
2023-07-31 19:10:34 +02:00
2023-07-31 20:09:03 +02:00
assert_eq! ( logbook_with_details [ 0 ] . logbook , logbook ) ;
2023-07-31 19:10:34 +02:00
}
#[ sqlx::test ]
fn test_completed ( ) {
let pool = testdb! ( ) ;
let completed = Logbook ::completed ( & pool ) . await ;
assert_eq! (
completed [ 0 ] . logbook ,
Logbook ::find_by_id ( & pool , 3 ) . await . unwrap ( )
) ;
assert_eq! (
completed [ 1 ] . logbook ,
Logbook ::find_by_id ( & pool , 2 ) . await . unwrap ( )
) ;
}
//#[sqlx::test]
//fn test_all() {
// let pool = testdb!();
// let res = Boat::all(&pool).await;
// assert!(res.len() > 3);
//}
#[ sqlx::test ]
fn test_succ_create ( ) {
let pool = testdb! ( ) ;
Logbook ::create (
& pool ,
LogToAdd {
boat_id : 3 ,
2023-10-01 15:53:45 +02:00
shipmaster : 4 ,
2023-10-29 18:42:12 +01:00
steering_person : 4 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 4 ] ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 4 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await
. unwrap ( )
}
#[ sqlx::test ]
fn test_create_boat_not_found ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 999 ,
shipmaster : 5 ,
2023-10-29 18:42:12 +01:00
steering_person : 5 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 5 ] ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 4 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await ;
assert_eq! ( res , Err ( LogbookCreateError ::BoatNotFound ) ) ;
}
#[ sqlx::test ]
fn test_create_boat_locked ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 5 ,
shipmaster : 5 ,
2023-10-29 18:42:12 +01:00
steering_person : 5 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 5 ] ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 4 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await ;
assert_eq! ( res , Err ( LogbookCreateError ::BoatLocked ) ) ;
}
#[ sqlx::test ]
fn test_create_boat_on_water ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 2 ,
shipmaster : 5 ,
2023-10-29 18:42:12 +01:00
steering_person : 5 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 5 ] ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 5 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await ;
assert_eq! ( res , Err ( LogbookCreateError ::BoatAlreadyOnWater ) ) ;
}
2023-09-24 09:48:01 +02:00
#[ sqlx::test ]
fn test_create_boat_on_water_wrong_arrival ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 3 ,
shipmaster : 5 ,
2023-10-29 18:42:12 +01:00
steering_person : 5 ,
2023-09-24 09:48:01 +02:00
shipmaster_only_steering : false ,
2023-09-29 13:36:36 +02:00
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : Some ( " 2128-05-20T11:00 " . into ( ) ) ,
2023-09-24 09:48:01 +02:00
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 5 ] ,
2023-09-24 09:48:01 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 5 ) . await . unwrap ( ) ,
2023-09-24 09:48:01 +02:00
)
. await ;
2023-10-29 20:41:30 +01:00
assert_eq! ( res , Err ( LogbookCreateError ::ArrivalSetButNotRemainingTwo ) ) ;
2023-09-24 09:48:01 +02:00
}
2023-07-31 19:10:34 +02:00
#[ sqlx::test ]
2023-10-29 20:41:30 +01:00
fn test_create_shipmaster_not_in_rowers ( ) {
2023-07-31 19:10:34 +02:00
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 3 ,
shipmaster : 2 ,
2023-10-29 18:42:12 +01:00
steering_person : 2 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-09-23 18:26:04 +02:00
rowers : Vec ::new ( ) ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 2 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await ;
2023-10-29 20:41:30 +01:00
assert_eq! ( res , Err ( LogbookCreateError ::ShipmasterNotInRowers ) ) ;
2023-07-31 19:10:34 +02:00
}
2023-09-24 09:12:27 +02:00
#[ sqlx::test ]
2023-10-29 20:41:30 +01:00
fn test_create_steering_person_not_in_rowers ( ) {
2023-09-24 09:12:27 +02:00
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 3 ,
shipmaster : 5 ,
2023-10-29 20:41:30 +01:00
steering_person : 1 ,
2023-09-24 09:12:27 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
rowers : vec ! [ 5 ] ,
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 5 ) . await . unwrap ( ) ,
2023-09-24 09:12:27 +02:00
)
. await ;
2023-10-29 20:41:30 +01:00
assert_eq! ( res , Err ( LogbookCreateError ::SteeringPersonNotInRowers ) ) ;
2023-09-24 09:12:27 +02:00
}
2023-07-31 19:10:34 +02:00
#[ sqlx::test ]
fn test_create_too_many_rowers ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::create (
& pool ,
LogToAdd {
boat_id : 1 ,
shipmaster : 5 ,
2023-10-29 18:42:12 +01:00
steering_person : 5 ,
2023-07-31 19:10:34 +02:00
shipmaster_only_steering : false ,
departure : " 2128-05-20T12:00 " . into ( ) ,
arrival : None ,
destination : None ,
distance_in_km : None ,
comments : None ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 1 , 5 ] ,
2023-07-31 19:10:34 +02:00
} ,
2023-10-01 15:53:45 +02:00
& User ::find_by_id ( & pool , 5 ) . await . unwrap ( ) ,
2023-07-31 19:10:34 +02:00
)
. await ;
assert_eq! ( res , Err ( LogbookCreateError ::TooManyRowers ( 1 , 2 ) ) ) ;
}
#[ sqlx::test ]
fn test_distances ( ) {
let pool = testdb! ( ) ;
let res = Logbook ::distances ( & pool ) . await ;
assert_eq! (
res ,
vec! [
( " Ottensheim " . into ( ) , 25 as i64 ) ,
( " Ottensheim + Regattastrecke " . into ( ) , 29 as i64 ) ,
]
) ;
}
#[ sqlx::test ]
fn test_succ_home ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
let user = User ::find_by_id ( & pool , 2 ) . await . unwrap ( ) ;
logbook
. home (
& pool ,
& user ,
super ::LogToFinalize {
destination : " new-destination " . into ( ) ,
distance_in_km : 42 ,
comments : Some ( " Perfect water " . into ( ) ) ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 2 ] ,
2023-10-29 18:42:12 +01:00
shipmaster : 2 ,
steering_person : 2 ,
shipmaster_only_steering : false ,
departure : " 1990-01-01T10:00 " . into ( ) ,
arrival : " 1990-01-01T12:00 " . into ( ) ,
2023-07-31 19:10:34 +02:00
} ,
)
. await
. unwrap ( ) ;
}
#[ sqlx::test ]
fn test_home_wrong_user ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
let user = User ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
let res = logbook
. home (
& pool ,
& user ,
super ::LogToFinalize {
destination : " new-destination " . into ( ) ,
distance_in_km : 42 ,
comments : Some ( " Perfect water " . into ( ) ) ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 1 ] ,
2023-10-29 18:42:12 +01:00
shipmaster : 1 ,
steering_person : 1 ,
shipmaster_only_steering : false ,
departure : " 1990-01-01T10:00 " . into ( ) ,
arrival : " 1990-01-01T12:00 " . into ( ) ,
2023-07-31 19:10:34 +02:00
} ,
)
. await ;
assert_eq! ( res , Err ( LogbookUpdateError ::NotYourEntry ) ) ;
}
#[ sqlx::test ]
fn test_home_too_many_rower ( ) {
let pool = testdb! ( ) ;
let logbook = Logbook ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
let user = User ::find_by_id ( & pool , 2 ) . await . unwrap ( ) ;
let res = logbook
. home (
& pool ,
& user ,
super ::LogToFinalize {
destination : " new-destination " . into ( ) ,
distance_in_km : 42 ,
comments : Some ( " Perfect water " . into ( ) ) ,
logtype : None ,
2023-10-29 20:41:30 +01:00
rowers : vec ! [ 1 , 2 ] ,
2023-10-29 18:42:12 +01:00
shipmaster : 2 ,
steering_person : 2 ,
shipmaster_only_steering : false ,
departure : " 1990-01-01T10:00 " . into ( ) ,
arrival : " 1990-01-01T12:00 " . into ( ) ,
2023-07-31 19:10:34 +02:00
} ,
)
. await ;
assert_eq! ( res , Err ( LogbookUpdateError ::TooManyRowers ( 1 , 2 ) ) ) ;
}
}