diff --git a/migration.sql b/migration.sql index 95ff9bb..bba12c1 100644 --- a/migration.sql +++ b/migration.sql @@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS "trip_details" ( "day" TEXT NOT NULL, "allow_guests" boolean NOT NULL default false, "notes" TEXT, + "always_show" boolean NOT NULL default false, "trip_type_id" INTEGER, FOREIGN KEY(trip_type_id) REFERENCES trip_type(id) ); @@ -34,7 +35,6 @@ CREATE TABLE IF NOT EXISTS "planned_event" ( "planned_amount_cox" INTEGER unsigned NOT NULL, "trip_details_id" INTEGER NOT NULL, "created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP, - "always_show" boolean NOT NULL default false, FOREIGN KEY(trip_details_id) REFERENCES trip_details(id) ON DELETE CASCADE ); diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 0884be3..afc0d60 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -42,7 +42,7 @@ pub enum LogbookUpdateError { pub enum LogbookCreateError { BoatAlreadyOnWater, - BoatLocked + BoatLocked, } impl Logbook { @@ -124,7 +124,7 @@ impl Logbook { ) -> Result<(), LogbookCreateError> { //Check if boat is not locked //Check if boat is already on water - sqlx::query!( + let _ = sqlx::query!( "INSERT INTO logbook(boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?)", boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype ) diff --git a/src/model/mod.rs b/src/model/mod.rs index df9ef27..9f914f6 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -33,10 +33,14 @@ impl Day { true => PlannedEvent::get_pinned_for_day(db, day).await, false => PlannedEvent::get_for_day(db, day).await, }; + let trips = match is_pinned { + true => Trip::get_pinned_for_day(db, day).await, + false => Trip::get_for_day(db, day).await, + }; Self { day, planned_events, - trips: Trip::get_for_day(db, day).await, + trips, is_pinned, } } diff --git a/src/model/planned_event.rs b/src/model/planned_event.rs index 0180bc2..51cd58e 100644 --- a/src/model/planned_event.rs +++ b/src/model/planned_event.rs @@ -21,8 +21,8 @@ pub struct PlannedEvent { pub day: String, notes: Option, pub allow_guests: bool, - always_show: bool, trip_type_id: Option, + always_show: bool, } #[derive(Serialize)] @@ -105,21 +105,6 @@ WHERE day=?", ret } - pub async fn pinned_days(db: &SqlitePool, amount_days_to_skip: i64) -> Vec { - let query = format!( - "SELECT DISTINCT day -FROM planned_event -INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id -WHERE always_show=true AND day > datetime('now' , '+{} days') -ORDER BY day;", - amount_days_to_skip - ); - let days: Vec = sqlx::query_scalar(&query).fetch_all(db).await.unwrap(); - days.into_iter() - .map(|a| NaiveDate::parse_from_str(&a, "%Y-%m-%d").unwrap()) - .collect() - } - pub async fn all(db: &SqlitePool) -> Vec { sqlx::query_as!( PlannedEvent, @@ -189,15 +174,13 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even db: &SqlitePool, name: &str, planned_amount_cox: i32, - always_show: bool, trip_details: TripDetails, ) { sqlx::query!( - "INSERT INTO planned_event(name, planned_amount_cox, trip_details_id, always_show) VALUES(?, ?, ?, ?)", + "INSERT INTO planned_event(name, planned_amount_cox, trip_details_id) VALUES(?, ?, ?)", name, planned_amount_cox, trip_details.id, - always_show ) .execute(db) .await @@ -214,9 +197,8 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even always_show: bool, ) { sqlx::query!( - "UPDATE planned_event SET planned_amount_cox = ?, always_show=? WHERE id = ?", + "UPDATE planned_event SET planned_amount_cox = ? WHERE id = ?", planned_amount_cox, - always_show, self.id ) .execute(db) @@ -224,9 +206,10 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even .unwrap(); //Okay, as planned_event can only be created with proper DB backing sqlx::query!( - "UPDATE trip_details SET max_people = ?, notes = ? WHERE id = ?", + "UPDATE trip_details SET max_people = ?, notes = ?, always_show=? WHERE id = ?", max_people, notes, + always_show, self.trip_details_id ) .execute(db) @@ -284,7 +267,7 @@ mod test { let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap(); - PlannedEvent::create(&pool, "new-event".into(), 2, false, trip_details).await; + PlannedEvent::create(&pool, "new-event".into(), 2, trip_details).await; let res = PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await; diff --git a/src/model/trip.rs b/src/model/trip.rs index 9df89f8..a7671a6 100644 --- a/src/model/trip.rs +++ b/src/model/trip.rs @@ -21,6 +21,7 @@ pub struct Trip { pub notes: Option, pub allow_guests: bool, trip_type_id: Option, + always_show: bool, } #[derive(Serialize)] @@ -47,7 +48,7 @@ impl Trip { sqlx::query_as!( Self, " -SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id +SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id, always_show FROM trip INNER JOIN trip_details ON trip.trip_details_id = trip_details.id INNER JOIN user ON trip.cox_id = user.id @@ -88,7 +89,7 @@ WHERE trip.id=? let trips = sqlx::query_as!( Trip, " -SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id +SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id, always_show FROM trip INNER JOIN trip_details ON trip.trip_details_id = trip_details.id INNER JOIN user ON trip.cox_id = user.id @@ -139,6 +140,7 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i max_people: i32, notes: Option<&str>, trip_type: Option, //TODO: Move to `TripType` + always_show: bool, ) -> Result<(), TripUpdateError> { if !trip.is_trip_from_user(cox.id) { return Err(TripUpdateError::NotYourTrip); @@ -156,10 +158,11 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i }; sqlx::query!( - "UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ? WHERE id = ?", + "UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ?, always_show = ? WHERE id = ?", max_people, notes, trip_type, + always_show, trip_details_id ) .execute(db) @@ -213,6 +216,15 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i fn is_trip_from_user(&self, user_id: i64) -> bool { self.cox_id == user_id } + + pub(crate) async fn get_pinned_for_day( + db: &sqlx::Pool, + day: NaiveDate, + ) -> Vec { + let mut trips = Self::get_for_day(db, day).await; + trips.retain(|e| e.trip.always_show); + trips + } } #[derive(Debug)] @@ -319,7 +331,7 @@ mod test { let trip = Trip::find_by_id(&pool, 1).await.unwrap(); - assert!(Trip::update_own(&pool, &cox, &trip, 10, None, None) + assert!(Trip::update_own(&pool, &cox, &trip, 10, None, None, false) .await .is_ok()); @@ -339,9 +351,11 @@ mod test { let trip = Trip::find_by_id(&pool, 1).await.unwrap(); - assert!(Trip::update_own(&pool, &cox, &trip, 10, None, Some(1)) - .await - .is_ok()); + assert!( + Trip::update_own(&pool, &cox, &trip, 10, None, Some(1), false) + .await + .is_ok() + ); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); assert_eq!(trip.max_people, 10); @@ -360,7 +374,7 @@ mod test { let trip = Trip::find_by_id(&pool, 1).await.unwrap(); - assert!(Trip::update_own(&pool, &cox, &trip, 10, None, None) + assert!(Trip::update_own(&pool, &cox, &trip, 10, None, None, false) .await .is_err()); assert_eq!(trip.max_people, 1); diff --git a/src/model/tripdetails.rs b/src/model/tripdetails.rs index 0585679..986b80a 100644 --- a/src/model/tripdetails.rs +++ b/src/model/tripdetails.rs @@ -1,3 +1,4 @@ +use chrono::NaiveDate; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, SqlitePool}; @@ -10,6 +11,7 @@ pub struct TripDetails { notes: Option, pub allow_guests: bool, trip_type_id: Option, + always_show: bool, } impl TripDetails { @@ -17,7 +19,7 @@ impl TripDetails { sqlx::query_as!( TripDetails, " -SELECT id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id +SELECT id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id, always_show FROM trip_details WHERE id like ? ", @@ -37,15 +39,17 @@ WHERE id like ? notes: Option<&str>, allow_guests: bool, trip_type_id: Option, + always_show: bool, ) -> i64 { let query = sqlx::query!( - "INSERT INTO trip_details(planned_starting_time, max_people, day, notes, allow_guests, trip_type_id) VALUES(?, ?, ?, ?, ?, ?)" , + "INSERT INTO trip_details(planned_starting_time, max_people, day, notes, allow_guests, trip_type_id, always_show) VALUES(?, ?, ?, ?, ?, ?, ?)" , planned_starting_time, max_people, day, notes, allow_guests, - trip_type_id + trip_type_id, + always_show ) .execute(db) .await @@ -65,6 +69,20 @@ WHERE id like ? amount_currently_registered >= self.max_people } + + pub async fn pinned_days(db: &SqlitePool, amount_days_to_skip: i64) -> Vec { + let query = format!( + "SELECT DISTINCT day +FROM trip_details +WHERE always_show=true AND day > datetime('now' , '+{} days') +ORDER BY day;", + amount_days_to_skip + ); + let days: Vec = sqlx::query_scalar(&query).fetch_all(db).await.unwrap(); + days.into_iter() + .map(|a| NaiveDate::parse_from_str(&a, "%Y-%m-%d").unwrap()) + .collect() + } } #[cfg(test)] @@ -100,7 +118,8 @@ mod test { "1970-01-01".into(), None, false, - None + None, + false ) .await, 3, @@ -113,7 +132,8 @@ mod test { "1970-01-01".into(), None, false, - None + None, + false ) .await, 4, diff --git a/src/model/user.rs b/src/model/user.rs index 4172ff6..3e13b54 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use sqlx::{FromRow, SqlitePool}; -use super::{planned_event::PlannedEvent, Day}; +use super::{tripdetails::TripDetails, Day}; #[derive(FromRow, Debug, Serialize, Deserialize)] pub struct User { @@ -209,7 +209,7 @@ ORDER BY last_access DESC } } - for date in PlannedEvent::pinned_days(db, self.amount_days_to_show()).await { + for date in TripDetails::pinned_days(db, self.amount_days_to_show()).await { if self.is_guest { let day = Day::new_guest(db, date, true).await; if !day.planned_events.is_empty() { diff --git a/src/model/usertrip.rs b/src/model/usertrip.rs index a12cab7..10a27ca 100644 --- a/src/model/usertrip.rs +++ b/src/model/usertrip.rs @@ -18,6 +18,8 @@ impl UserTrip { return Err(UserTripError::GuestNotAllowedForThisEvent); } + //TODO: Check if user sees the event (otherwise she could forge trip_details_id + //check if cox if own event let is_cox = sqlx::query!( "SELECT count(*) as amount diff --git a/src/tera/admin/planned_event.rs b/src/tera/admin/planned_event.rs index c1bba28..6e1a609 100644 --- a/src/tera/admin/planned_event.rs +++ b/src/tera/admin/planned_event.rs @@ -36,6 +36,7 @@ async fn create( data.notes, data.allow_guests, data.trip_type, + data.always_show, ) .await; @@ -43,14 +44,7 @@ async fn create( //just created //the object - PlannedEvent::create( - db, - data.name, - data.planned_amount_cox, - data.always_show, - trip_details, - ) - .await; + PlannedEvent::create(db, data.name, data.planned_amount_cox, trip_details).await; Flash::success(Redirect::to("/"), "Successfully planned the event") } diff --git a/src/tera/cox.rs b/src/tera/cox.rs index fb2237f..96f1772 100644 --- a/src/tera/cox.rs +++ b/src/tera/cox.rs @@ -24,6 +24,7 @@ struct AddTripForm<'r> { notes: Option<&'r str>, trip_type: Option, allow_guests: bool, + always_show: bool, } #[post("/trip", data = "")] @@ -40,6 +41,7 @@ async fn create( data.notes, data.allow_guests, data.trip_type, + data.always_show, ) .await; let trip_details = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); //Okay, bc just @@ -63,6 +65,7 @@ struct EditTripForm<'r> { max_people: i32, notes: Option<&'r str>, trip_type: Option, + always_show: bool, } #[post("/trip/", data = "")] @@ -73,7 +76,17 @@ async fn update( cox: CoxUser, ) -> Flash { if let Some(trip) = Trip::find_by_id(db, trip_id).await { - match Trip::update_own(db, &cox, &trip, data.max_people, data.notes, data.trip_type).await { + match Trip::update_own( + db, + &cox, + &trip, + data.max_people, + data.notes, + data.trip_type, + data.always_show, + ) + .await + { Ok(_) => Flash::success(Redirect::to("/"), "Ausfahrt erfolgreich aktualisiert."), Err(TripUpdateError::NotYourTrip) => { Flash::error(Redirect::to("/"), "Nicht deine Ausfahrt!") diff --git a/templates/forms/trip.html.tera b/templates/forms/trip.html.tera index 8b7d0b5..d1af987 100644 --- a/templates/forms/trip.html.tera +++ b/templates/forms/trip.html.tera @@ -6,6 +6,7 @@ {{ macros::input(label='Startzeit (zB "10:00")', name='planned_starting_time', type='time', required=true) }} {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='max_people', type='number', required=true, min='0') }} {{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }} + {{ macros::checkbox(label='Immer anzeigen', name='always_show') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }} {{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }} diff --git a/templates/index.html.tera b/templates/index.html.tera index 95c712e..0f6eed6 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -128,7 +128,7 @@ {{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=planned_event.max_people, min='0') }} {{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', value=planned_event.planned_amount_cox, required=true, min='0') }} - {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=planned_event.id,checked=planned_event.always_show) }} + {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=planned_event.id,checked=planned_event.always_show) }} {{ macros::input(label='Anmerkungen', name='notes', type='input', value=planned_event.notes) }} @@ -210,6 +210,7 @@
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min='0') }} {{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }} + {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=trip.id,checked=trip.always_show) }} {{ macros::select(select_name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}