diff --git a/src/model/boat.rs b/src/model/boat.rs index e939493..f5a1d2d 100644 --- a/src/model/boat.rs +++ b/src/model/boat.rs @@ -1,6 +1,6 @@ use rocket::serde::{Deserialize, Serialize}; use rocket::FromForm; -use sqlx::{FromRow, SqlitePool}; +use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; use super::user::User; @@ -70,6 +70,12 @@ impl Boat { .await .ok() } + pub async fn find_by_id_tx(db: &mut Transaction<'_, Sqlite>, id: i32) -> Option { + sqlx::query_as!(Self, "SELECT * FROM boat WHERE id like ?", id) + .fetch_one(db) + .await + .ok() + } pub async fn find_by_name(db: &SqlitePool, name: String) -> Option { sqlx::query_as!(Self, "SELECT * FROM boat WHERE name like ?", name) diff --git a/src/model/log.rs b/src/model/log.rs index b862c79..3b9b4a8 100644 --- a/src/model/log.rs +++ b/src/model/log.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, Local, NaiveDateTime, TimeZone, Utc}; use serde::{Deserialize, Serialize}; -use sqlx::{FromRow, SqlitePool}; +use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; #[derive(FromRow, Debug, Serialize, Deserialize)] pub struct Log { @@ -15,6 +15,12 @@ impl Log { .await .is_ok() } + pub async fn create_with_tx(db: &mut Transaction<'_, Sqlite>, msg: String) -> bool { + sqlx::query!("INSERT INTO log(msg) VALUES (?)", msg,) + .execute(db) + .await + .is_ok() + } async fn last(db: &SqlitePool) -> Vec { sqlx::query_as!( diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 5d2e763..9729a59 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -1,5 +1,4 @@ -use chrono::{NaiveDateTime, TimeZone}; -use chrono_tz::Europe::Vienna; +use chrono::NaiveDateTime; use rocket::FromForm; use serde::Serialize; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; @@ -28,7 +27,7 @@ impl PartialEq for Logbook { } } -#[derive(FromForm, Debug)] +#[derive(FromForm, Debug, Clone)] pub struct LogToAdd { pub boat_id: i32, pub shipmaster: i64, @@ -57,6 +56,30 @@ pub struct LogToFinalize { pub rowers: Vec, } +impl TryFrom for LogToFinalize { + type Error = String; + + fn try_from(value: LogToAdd) -> Result { + 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()) + } +} + #[derive(Serialize, Debug)] pub struct LogbookWithBoatAndRowers { #[serde(flatten)] @@ -73,6 +96,9 @@ pub enum LogbookUpdateError { TooManyRowers(usize, usize), RowerCreateError(i64, String), ArrivalNotAfterDeparture, + ShipmasterNotInRowers, + SteeringPersonNotInRowers, + UserNotAllowedToUseBoat, } #[derive(Debug, PartialEq)] @@ -82,18 +108,40 @@ pub enum LogbookDeleteError { #[derive(Debug, PartialEq)] pub enum LogbookCreateError { - ArrivalSetButNoDestination, UserNotAllowedToUseBoat, - ArrivalSetButNoDistance, BoatAlreadyOnWater, BoatLocked, BoatNotFound, TooManyRowers(usize, usize), - ShipmasterAlreadyOnWater, RowerAlreadyOnWater(User), RowerCreateError(i64, String), - SamePersonShipmasterAndRower, ArrivalNotAfterDeparture, + SteeringPersonNotInRowers, + ShipmasterNotInRowers, + NotYourEntry, + ArrivalSetButNotRemainingTwo, +} + +impl From 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 + } + }; + } } impl Logbook { @@ -115,7 +163,7 @@ impl Logbook { pub async fn on_water(db: &SqlitePool) -> Vec { let rows = sqlx::query!( " -SELECT id, boat_id, shipmaster,steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype +SELECT id, boat_id, shipmaster, steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype FROM logbook WHERE arrival is null ORDER BY departure DESC @@ -191,6 +239,44 @@ ORDER BY departure DESC log: LogToAdd, created_by_user: &User, ) -> Result<(), LogbookCreateError> { + println!("{log:#?}"); + if let Ok(log_to_finalize) = TryInto::::try_into(log.clone()) { + //TODO: fix clone() + 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); + } + let Some(boat) = Boat::find_by_id(db, log.boat_id).await else { return Err(LogbookCreateError::BoatNotFound); }; @@ -203,39 +289,22 @@ ORDER BY departure DESC return Err(LogbookCreateError::BoatAlreadyOnWater); } - let shipmaster = User::find_by_id(db, log.shipmaster as i32).await.unwrap(); - - if shipmaster.on_water(db).await { - return Err(LogbookCreateError::ShipmasterAlreadyOnWater); + if !log.rowers.contains(&log.shipmaster) { + return Err(LogbookCreateError::ShipmasterNotInRowers); + } + if !log.rowers.contains(&log.steering_person) { + return Err(LogbookCreateError::SteeringPersonNotInRowers); } - if let Some(arrival) = &log.arrival { - 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 { + if log.rowers.len() > boat.amount_seats as usize { return Err(LogbookCreateError::TooManyRowers( boat.amount_seats as usize, - log.rowers.len() + 1, + log.rowers.len(), )); } for rower in &log.rowers { let user = User::find_by_id(db, *rower as i32).await.unwrap(); - if *rower == log.shipmaster { - return Err(LogbookCreateError::SamePersonShipmasterAndRower); - } if user.on_water(db).await { return Err(LogbookCreateError::RowerAlreadyOnWater(user)); @@ -251,21 +320,6 @@ ORDER BY departure DESC let mut tx = db.begin().await.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, steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?,?) RETURNING id", log.boat_id, @@ -335,51 +389,80 @@ ORDER BY departure DESC user: &User, log: LogToFinalize, ) -> Result<(), LogbookUpdateError> { + 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()` if user.id != self.shipmaster { return Err(LogbookUpdateError::NotYourEntry); } - let boat = Boat::find_by_id(db, self.boat_id as i32).await.unwrap(); //ok + if !log.rowers.contains(&log.shipmaster) { + return Err(LogbookUpdateError::ShipmasterNotInRowers); + } + if !log.rowers.contains(&log.steering_person) { + return Err(LogbookUpdateError::SteeringPersonNotInRowers); + } - if log.rowers.len() > boat.amount_seats as usize - 1 { + 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 { return Err(LogbookUpdateError::TooManyRowers( boat.amount_seats as usize, - log.rowers.len() + 1, + log.rowers.len(), )); } - 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 + 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() { return Err(LogbookUpdateError::ArrivalNotAfterDeparture); } - Log::create(db, format!("New trip: {log:?}")).await; - let mut tx = db.begin().await.unwrap(); - - sqlx::query!( - "UPDATE logbook SET destination=?, distance_in_km=?, comments=?, logtype=?, arrival=? WHERE id=?", - log.destination, - log.distance_in_km, - log.comments, - log.logtype, - arrival, - self.id - ) - .execute(&mut tx) - .await.unwrap(); //TODO: fixme - - self.remove_rowers(&mut tx).await; + Log::create_with_tx(db, format!("New trip: {log:?}")).await; + self.remove_rowers(db).await; for rower in &log.rowers { - Rower::create(&mut tx, self.id, *rower) + Rower::create(db, self.id, *rower) .await .map_err(|e| LogbookUpdateError::RowerCreateError(*rower, e.to_string()))?; } - tx.commit().await.unwrap(); + sqlx::query!( + "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, + log.destination, + log.distance_in_km, + log.comments, + log.logtype, + log.arrival, + self.id + ) + .execute(db) + .await.unwrap(); //TODO: fixme Ok(()) } @@ -468,7 +551,7 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: Vec::new(), + rowers: vec![4], }, &User::find_by_id(&pool, 4).await.unwrap(), ) @@ -493,7 +576,7 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: Vec::new(), + rowers: vec![5], }, &User::find_by_id(&pool, 4).await.unwrap(), ) @@ -519,7 +602,7 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: Vec::new(), + rowers: vec![5], }, &User::find_by_id(&pool, 4).await.unwrap(), ) @@ -545,7 +628,7 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: Vec::new(), + rowers: vec![5], }, &User::find_by_id(&pool, 5).await.unwrap(), ) @@ -571,17 +654,17 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: Vec::new(), + rowers: vec![5], }, &User::find_by_id(&pool, 5).await.unwrap(), ) .await; - assert_eq!(res, Err(LogbookCreateError::ArrivalNotAfterDeparture)); + assert_eq!(res, Err(LogbookCreateError::ArrivalSetButNotRemainingTwo)); } #[sqlx::test] - fn test_create_shipmaster_on_water() { + fn test_create_shipmaster_not_in_rowers() { let pool = testdb!(); let res = Logbook::create( @@ -603,11 +686,11 @@ mod test { ) .await; - assert_eq!(res, Err(LogbookCreateError::ShipmasterAlreadyOnWater)); + assert_eq!(res, Err(LogbookCreateError::ShipmasterNotInRowers)); } #[sqlx::test] - fn test_create_same_person_cox_and_rower() { + fn test_create_steering_person_not_in_rowers() { let pool = testdb!(); let res = Logbook::create( @@ -615,7 +698,7 @@ mod test { LogToAdd { boat_id: 3, shipmaster: 5, - steering_person: 5, + steering_person: 1, shipmaster_only_steering: false, departure: "2128-05-20T12:00".into(), arrival: None, @@ -629,7 +712,7 @@ mod test { ) .await; - assert_eq!(res, Err(LogbookCreateError::SamePersonShipmasterAndRower)); + assert_eq!(res, Err(LogbookCreateError::SteeringPersonNotInRowers)); } #[sqlx::test] @@ -649,7 +732,7 @@ mod test { distance_in_km: None, comments: None, logtype: None, - rowers: vec![1], + rowers: vec![1, 5], }, &User::find_by_id(&pool, 5).await.unwrap(), ) @@ -689,7 +772,7 @@ mod test { distance_in_km: 42, comments: Some("Perfect water".into()), logtype: None, - rowers: vec![], + rowers: vec![2], shipmaster: 2, steering_person: 2, shipmaster_only_steering: false, @@ -717,7 +800,7 @@ mod test { distance_in_km: 42, comments: Some("Perfect water".into()), logtype: None, - rowers: vec![], + rowers: vec![1], shipmaster: 1, steering_person: 1, shipmaster_only_steering: false, @@ -746,7 +829,7 @@ mod test { distance_in_km: 42, comments: Some("Perfect water".into()), logtype: None, - rowers: vec![1], + rowers: vec![1, 2], shipmaster: 2, steering_person: 2, shipmaster_only_steering: false, diff --git a/src/model/user.rs b/src/model/user.rs index 8a0dc85..8a6366d 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -11,7 +11,7 @@ use rocket::{ Request, }; use serde::{Deserialize, Serialize}; -use sqlx::{FromRow, SqlitePool}; +use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; use super::{log::Log, tripdetails::TripDetails, Day}; @@ -103,6 +103,21 @@ WHERE id like ? .ok() } + pub async fn find_by_id_tx(db: &mut Transaction<'_, Sqlite>, id: i32) -> Option { + sqlx::query_as!( + Self, + " +SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech +FROM user +WHERE id like ? + ", + id + ) + .fetch_one(db) + .await + .ok() + } + pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option { sqlx::query_as!( Self, diff --git a/src/tera/log.rs b/src/tera/log.rs index b3787dc..1e2bdbb 100644 --- a/src/tera/log.rs +++ b/src/tera/log.rs @@ -171,17 +171,17 @@ async fn create_logbook( { Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt erfolgreich hinzugefügt"), Err(LogbookCreateError::BoatAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Boot schon am Wasser"), - Err(LogbookCreateError::ShipmasterAlreadyOnWater) => Flash::error(Redirect::to("/log"), "Schiffsführer 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"), Err(LogbookCreateError::BoatNotFound) => Flash::error(Redirect::to("/log"), "Boot gibt's ned"), Err(LogbookCreateError::TooManyRowers(expected, actual)) => 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"), "Selbe Person als Schiffsführer und Ruderer ausgewählt"), - Err(LogbookCreateError::ArrivalSetButNoDistance) => Flash::error(Redirect::to("/log"), "Distanz notwendig, wenn Ankunftszeit angegeben wurde"), - Err(LogbookCreateError::ArrivalSetButNoDestination) => Flash::error(Redirect::to("/log"), "Ziel notwendig, wenn Ankunftszeit angegeben wurde"), Err(LogbookCreateError::ArrivalNotAfterDeparture) => Flash::error(Redirect::to("/log"), "Ankunftszeit kann nicht vor der Abfahrtszeit sein"), Err(LogbookCreateError::UserNotAllowedToUseBoat) => Flash::error(Redirect::to("/log"), "Schiffsführer darf dieses Boot nicht verwenden"), + Err(LogbookCreateError::SteeringPersonNotInRowers) => Flash::error(Redirect::to("/log"), "Steuerperson nicht in Liste der Ruderer!"), + Err(LogbookCreateError::ShipmasterNotInRowers) => Flash::error(Redirect::to("/log"), "Schiffsführer nicht in Liste der Ruderer!"), + Err(LogbookCreateError::NotYourEntry) => Flash::error(Redirect::to("/log"), "Nicht deine Ausfahrt!"), + Err(LogbookCreateError::ArrivalSetButNotRemainingTwo) => Flash::error(Redirect::to("/log"), "Ankunftszeit gesetzt aber nicht Distanz + Strecke"), } } @@ -240,9 +240,9 @@ async fn home_logbook( match logbook.home(db, &user.user, data.into_inner()).await { Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt korrekt eingetragen"), 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(e) => Flash::error( Redirect::to("/log"), - format!("Eintrag {} konnte nicht abgesendet werden!", logbook_id), + format!("Eintrag {logbook_id} konnte nicht abgesendet werden (Fehler: {e:?})!"), ), } } @@ -515,7 +515,7 @@ mod test { let req = client .post("/log") .header(ContentType::Form) - .body("boat_id=1&shipmaster=4&departure=2199-12-31T10:00&steering_person=4"); + .body("boat_id=1&shipmaster=4&departure=2199-12-31T10:00&steering_person=4&rowers[]=4"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); @@ -546,7 +546,7 @@ mod test { let req = client .post("/log/1") .header(ContentType::Form) - .body("destination=Ottensheim&distance_in_km=25&shipmaster=1&steering_person=1&departure=1990-01-01T10:00&arrival=1990-01-01T12:00"); + .body("destination=Ottensheim&distance_in_km=25&shipmaster=2&steering_person=2&departure=1990-01-01T10:00&arrival=1990-01-01T12:00&rowers[]=2"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); @@ -655,7 +655,7 @@ mod test { let shipmaster_id = User::find_by_name(&db, "rower2".into()).await.unwrap().id; let req = client.post("/log").header(ContentType::Form).body(format!( - "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00&steering_person={shipmaster_id}" + "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00&steering_person={shipmaster_id}&rowers[]={shipmaster_id}" )); let response = req.dispatch().await; @@ -684,7 +684,7 @@ mod test { let req = client .post(format!("/log/{log_id}")) .header(ContentType::Form) - .body(format!("destination=Ottensheim&distance_in_km=25&shipmaster={shipmaster_id}&steering_person={shipmaster_id}&departure=1990-01-01T10:00&arrival=1990-01-01T12:00")); + .body(format!("destination=Ottensheim&distance_in_km=25&shipmaster={shipmaster_id}&steering_person={shipmaster_id}&departure=1990-01-01T10:00&arrival=1990-01-01T12:00&rowers[]={shipmaster_id}")); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); @@ -875,7 +875,7 @@ mod test { let req = client .post("/log/1") .header(ContentType::Form) - .body("destination=Ottensheim&distance_in_km=25&shipmaster=1&steering_person=1&departure=1199-12-12T10:00&arrival=1199-12-12T12:00"); + .body("destination=Ottensheim&distance_in_km=25&shipmaster=1&steering_person=1&departure=1199-12-12T10:00&arrival=1199-12-12T12:00&rowers[]=1"); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); @@ -888,7 +888,7 @@ mod test { assert_eq!( flash_cookie.value(), - "5:errorEintrag 1 konnte nicht abgesendet werden!" + "5:errorEintrag 1 konnte nicht abgesendet werden (Fehler: NotYourEntry)!" ); } @@ -902,7 +902,7 @@ mod test { let shipmaster_id = User::find_by_name(db, &shipmaster_name).await.unwrap().id; let req = client.post("/log").header(ContentType::Form).body(format!( - "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00&steering_person={shipmaster_id}" + "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=1199-12-31T10:00&steering_person={shipmaster_id}&rowers[]={shipmaster_id}" )); let response = req.dispatch().await; @@ -924,7 +924,7 @@ mod test { let req = client .post(format!("/log/{log_id}")) .header(ContentType::Form) - .body(format!("destination=Ottensheim&distance_in_km=25&shipmaster={shipmaster_id}&steering_person={shipmaster_id}&departure=1199-12-31T10:00&arrival=1199-12-31T12:00")); + .body(format!("destination=Ottensheim&distance_in_km=25&shipmaster={shipmaster_id}&steering_person={shipmaster_id}&departure=1199-12-31T10:00&arrival=1199-12-31T12:00&rowers[]={shipmaster_id}")); let response = req.dispatch().await; assert_eq!(response.status(), Status::SeeOther); @@ -952,7 +952,7 @@ mod test { let shipmaster_id = User::find_by_name(db, &shipmaster_name).await.unwrap().id; let req = client.post("/log").header(ContentType::Form).body(format!( - "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=2199-12-31T10:00&steering_person={shipmaster_id}" + "boat_id={boat_id}&shipmaster={shipmaster_id}&departure=2199-12-31T10:00&steering_person={shipmaster_id}&rowers[]={shipmaster_id}" )); let response = req.dispatch().await;