Merge branch 'main' of gitlab.com:PhilippHofer/rot

This commit is contained in:
Philipp 2023-07-23 19:58:47 +02:00
commit 388be197e4
12 changed files with 84 additions and 52 deletions

View File

@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS "trip_details" (
"day" TEXT NOT NULL, "day" TEXT NOT NULL,
"allow_guests" boolean NOT NULL default false, "allow_guests" boolean NOT NULL default false,
"notes" TEXT, "notes" TEXT,
"always_show" boolean NOT NULL default false,
"trip_type_id" INTEGER, "trip_type_id" INTEGER,
FOREIGN KEY(trip_type_id) REFERENCES trip_type(id) 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, "planned_amount_cox" INTEGER unsigned NOT NULL,
"trip_details_id" INTEGER NOT NULL, "trip_details_id" INTEGER NOT NULL,
"created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP, "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 FOREIGN KEY(trip_details_id) REFERENCES trip_details(id) ON DELETE CASCADE
); );

View File

@ -42,7 +42,7 @@ pub enum LogbookUpdateError {
pub enum LogbookCreateError { pub enum LogbookCreateError {
BoatAlreadyOnWater, BoatAlreadyOnWater,
BoatLocked BoatLocked,
} }
impl Logbook { impl Logbook {
@ -124,7 +124,7 @@ impl Logbook {
) -> Result<(), LogbookCreateError> { ) -> Result<(), LogbookCreateError> {
//Check if boat is not locked //Check if boat is not locked
//Check if boat is already on water //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 (?,?,?,?,?,?,?,?,?)", "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 boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype
) )

View File

@ -33,10 +33,14 @@ impl Day {
true => PlannedEvent::get_pinned_for_day(db, day).await, true => PlannedEvent::get_pinned_for_day(db, day).await,
false => PlannedEvent::get_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 { Self {
day, day,
planned_events, planned_events,
trips: Trip::get_for_day(db, day).await, trips,
is_pinned, is_pinned,
} }
} }

View File

@ -21,8 +21,8 @@ pub struct PlannedEvent {
pub day: String, pub day: String,
notes: Option<String>, notes: Option<String>,
pub allow_guests: bool, pub allow_guests: bool,
always_show: bool,
trip_type_id: Option<i64>, trip_type_id: Option<i64>,
always_show: bool,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -105,21 +105,6 @@ WHERE day=?",
ret ret
} }
pub async fn pinned_days(db: &SqlitePool, amount_days_to_skip: i64) -> Vec<NaiveDate> {
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<String> = 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<PlannedEvent> { pub async fn all(db: &SqlitePool) -> Vec<PlannedEvent> {
sqlx::query_as!( sqlx::query_as!(
PlannedEvent, PlannedEvent,
@ -189,15 +174,13 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even
db: &SqlitePool, db: &SqlitePool,
name: &str, name: &str,
planned_amount_cox: i32, planned_amount_cox: i32,
always_show: bool,
trip_details: TripDetails, trip_details: TripDetails,
) { ) {
sqlx::query!( 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, name,
planned_amount_cox, planned_amount_cox,
trip_details.id, trip_details.id,
always_show
) )
.execute(db) .execute(db)
.await .await
@ -214,9 +197,8 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even
always_show: bool, always_show: bool,
) { ) {
sqlx::query!( 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, planned_amount_cox,
always_show,
self.id self.id
) )
.execute(db) .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 .unwrap(); //Okay, as planned_event can only be created with proper DB backing
sqlx::query!( sqlx::query!(
"UPDATE trip_details SET max_people = ?, notes = ? WHERE id = ?", "UPDATE trip_details SET max_people = ?, notes = ?, always_show=? WHERE id = ?",
max_people, max_people,
notes, notes,
always_show,
self.trip_details_id self.trip_details_id
) )
.execute(db) .execute(db)
@ -284,7 +267,7 @@ mod test {
let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap(); 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 = let res =
PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await; PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;

View File

@ -21,6 +21,7 @@ pub struct Trip {
pub notes: Option<String>, pub notes: Option<String>,
pub allow_guests: bool, pub allow_guests: bool,
trip_type_id: Option<i64>, trip_type_id: Option<i64>,
always_show: bool,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -47,7 +48,7 @@ impl Trip {
sqlx::query_as!( sqlx::query_as!(
Self, 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 FROM trip
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
INNER JOIN user ON trip.cox_id = user.id INNER JOIN user ON trip.cox_id = user.id
@ -88,7 +89,7 @@ WHERE trip.id=?
let trips = sqlx::query_as!( let trips = sqlx::query_as!(
Trip, 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 FROM trip
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
INNER JOIN user ON trip.cox_id = user.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, max_people: i32,
notes: Option<&str>, notes: Option<&str>,
trip_type: Option<i64>, //TODO: Move to `TripType` trip_type: Option<i64>, //TODO: Move to `TripType`
always_show: bool,
) -> Result<(), TripUpdateError> { ) -> Result<(), TripUpdateError> {
if !trip.is_trip_from_user(cox.id) { if !trip.is_trip_from_user(cox.id) {
return Err(TripUpdateError::NotYourTrip); 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!( 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, max_people,
notes, notes,
trip_type, trip_type,
always_show,
trip_details_id trip_details_id
) )
.execute(db) .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 { fn is_trip_from_user(&self, user_id: i64) -> bool {
self.cox_id == user_id self.cox_id == user_id
} }
pub(crate) async fn get_pinned_for_day(
db: &sqlx::Pool<sqlx::Sqlite>,
day: NaiveDate,
) -> Vec<TripWithUserAndType> {
let mut trips = Self::get_for_day(db, day).await;
trips.retain(|e| e.trip.always_show);
trips
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -319,7 +331,7 @@ mod test {
let trip = Trip::find_by_id(&pool, 1).await.unwrap(); 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 .await
.is_ok()); .is_ok());
@ -339,9 +351,11 @@ mod test {
let trip = Trip::find_by_id(&pool, 1).await.unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap();
assert!(Trip::update_own(&pool, &cox, &trip, 10, None, Some(1)) assert!(
Trip::update_own(&pool, &cox, &trip, 10, None, Some(1), false)
.await .await
.is_ok()); .is_ok()
);
let trip = Trip::find_by_id(&pool, 1).await.unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap();
assert_eq!(trip.max_people, 10); assert_eq!(trip.max_people, 10);
@ -360,7 +374,7 @@ mod test {
let trip = Trip::find_by_id(&pool, 1).await.unwrap(); 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 .await
.is_err()); .is_err());
assert_eq!(trip.max_people, 1); assert_eq!(trip.max_people, 1);

View File

@ -1,3 +1,4 @@
use chrono::NaiveDate;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
@ -10,6 +11,7 @@ pub struct TripDetails {
notes: Option<String>, notes: Option<String>,
pub allow_guests: bool, pub allow_guests: bool,
trip_type_id: Option<i64>, trip_type_id: Option<i64>,
always_show: bool,
} }
impl TripDetails { impl TripDetails {
@ -17,7 +19,7 @@ impl TripDetails {
sqlx::query_as!( sqlx::query_as!(
TripDetails, 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 FROM trip_details
WHERE id like ? WHERE id like ?
", ",
@ -37,15 +39,17 @@ WHERE id like ?
notes: Option<&str>, notes: Option<&str>,
allow_guests: bool, allow_guests: bool,
trip_type_id: Option<i64>, trip_type_id: Option<i64>,
always_show: bool,
) -> i64 { ) -> i64 {
let query = sqlx::query!( 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, planned_starting_time,
max_people, max_people,
day, day,
notes, notes,
allow_guests, allow_guests,
trip_type_id trip_type_id,
always_show
) )
.execute(db) .execute(db)
.await .await
@ -65,6 +69,20 @@ WHERE id like ?
amount_currently_registered >= self.max_people amount_currently_registered >= self.max_people
} }
pub async fn pinned_days(db: &SqlitePool, amount_days_to_skip: i64) -> Vec<NaiveDate> {
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<String> = 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)] #[cfg(test)]
@ -100,7 +118,8 @@ mod test {
"1970-01-01".into(), "1970-01-01".into(),
None, None,
false, false,
None None,
false
) )
.await, .await,
3, 3,
@ -113,7 +132,8 @@ mod test {
"1970-01-01".into(), "1970-01-01".into(),
None, None,
false, false,
None None,
false
) )
.await, .await,
4, 4,

View File

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
use super::{planned_event::PlannedEvent, Day}; use super::{tripdetails::TripDetails, Day};
#[derive(FromRow, Debug, Serialize, Deserialize)] #[derive(FromRow, Debug, Serialize, Deserialize)]
pub struct User { 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 { if self.is_guest {
let day = Day::new_guest(db, date, true).await; let day = Day::new_guest(db, date, true).await;
if !day.planned_events.is_empty() { if !day.planned_events.is_empty() {

View File

@ -18,6 +18,8 @@ impl UserTrip {
return Err(UserTripError::GuestNotAllowedForThisEvent); return Err(UserTripError::GuestNotAllowedForThisEvent);
} }
//TODO: Check if user sees the event (otherwise she could forge trip_details_id
//check if cox if own event //check if cox if own event
let is_cox = sqlx::query!( let is_cox = sqlx::query!(
"SELECT count(*) as amount "SELECT count(*) as amount

View File

@ -36,6 +36,7 @@ async fn create(
data.notes, data.notes,
data.allow_guests, data.allow_guests,
data.trip_type, data.trip_type,
data.always_show,
) )
.await; .await;
@ -43,14 +44,7 @@ async fn create(
//just created //just created
//the object //the object
PlannedEvent::create( PlannedEvent::create(db, data.name, data.planned_amount_cox, trip_details).await;
db,
data.name,
data.planned_amount_cox,
data.always_show,
trip_details,
)
.await;
Flash::success(Redirect::to("/"), "Successfully planned the event") Flash::success(Redirect::to("/"), "Successfully planned the event")
} }

View File

@ -24,6 +24,7 @@ struct AddTripForm<'r> {
notes: Option<&'r str>, notes: Option<&'r str>,
trip_type: Option<i64>, trip_type: Option<i64>,
allow_guests: bool, allow_guests: bool,
always_show: bool,
} }
#[post("/trip", data = "<data>")] #[post("/trip", data = "<data>")]
@ -40,6 +41,7 @@ async fn create(
data.notes, data.notes,
data.allow_guests, data.allow_guests,
data.trip_type, data.trip_type,
data.always_show,
) )
.await; .await;
let trip_details = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); //Okay, bc just 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, max_people: i32,
notes: Option<&'r str>, notes: Option<&'r str>,
trip_type: Option<i64>, trip_type: Option<i64>,
always_show: bool,
} }
#[post("/trip/<trip_id>", data = "<data>")] #[post("/trip/<trip_id>", data = "<data>")]
@ -73,7 +76,17 @@ async fn update(
cox: CoxUser, cox: CoxUser,
) -> Flash<Redirect> { ) -> Flash<Redirect> {
if let Some(trip) = Trip::find_by_id(db, trip_id).await { 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."), Ok(_) => Flash::success(Redirect::to("/"), "Ausfahrt erfolgreich aktualisiert."),
Err(TripUpdateError::NotYourTrip) => { Err(TripUpdateError::NotYourTrip) => {
Flash::error(Redirect::to("/"), "Nicht deine Ausfahrt!") Flash::error(Redirect::to("/"), "Nicht deine Ausfahrt!")

View File

@ -6,6 +6,7 @@
{{ macros::input(label='Startzeit (zB "10:00")', name='planned_starting_time', type='time', required=true) }} {{ 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::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='Gäste erlauben', name='allow_guests') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show') }}
{{ macros::input(label='Anmerkungen', name='notes', type='input') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
{{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }} {{ macros::select(data=trip_types, select_name='trip_type', default='Reguläre Ausfahrt') }}

View File

@ -210,6 +210,7 @@
<form action="/cox/trip/{{ trip.id }}" method="post" class="grid gap-3"> <form action="/cox/trip/{{ trip.id }}" method="post" class="grid gap-3">
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min='0') }} {{ 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::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) }} {{ macros::select(select_name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}
<input value="Speichern" class="btn btn-primary" type="submit" /> <input value="Speichern" class="btn btn-primary" type="submit" />