From de567eedec74265ede2b8f00528b969598be262e Mon Sep 17 00:00:00 2001 From: philipp Date: Fri, 25 Oct 2024 18:29:50 +0200 Subject: [PATCH 1/3] switch from cox to steeringuser, which contains both cox + bootsfuehrer --- src/model/notification.rs | 4 +-- src/model/trip.rs | 34 +++++++++++++------------- src/model/user.rs | 6 ++++- src/model/usertrip.rs | 8 +++--- src/tera/boatdamage.rs | 4 +-- src/tera/cox.rs | 16 +++++++----- templates/boatdamages.html.tera | 2 +- templates/includes/buttons.html.tera | 2 +- templates/includes/forms/log.html.tera | 2 +- templates/log.html.tera | 4 +-- templates/planned.html.tera | 12 ++++----- 11 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/model/notification.rs b/src/model/notification.rs index ab592c3..0b193ae 100644 --- a/src/model/notification.rs +++ b/src/model/notification.rs @@ -195,7 +195,7 @@ mod test { notification::Notification, trip::Trip, tripdetails::{TripDetails, TripDetailsToAdd}, - user::{CoxUser, User}, + user::{SteeringUser, User}, usertrip::UserTrip, }, testdb, @@ -231,7 +231,7 @@ mod test { UserTrip::create(&pool, &rower, &trip_details, None) .await .unwrap(); - let cox = CoxUser::new(&pool, User::find_by_name(&pool, "cox").await.unwrap()) + let cox = SteeringUser::new(&pool, User::find_by_name(&pool, "cox").await.unwrap()) .await .unwrap(); Trip::new_join(&pool, &cox, &event).await.unwrap(); diff --git a/src/model/trip.rs b/src/model/trip.rs index dfeacc4..cefb1ce 100644 --- a/src/model/trip.rs +++ b/src/model/trip.rs @@ -9,7 +9,7 @@ use super::{ notification::Notification, tripdetails::TripDetails, triptype::TripType, - user::{CoxUser, User}, + user::{SteeringUser, User}, usertrip::UserTrip, }; @@ -38,7 +38,7 @@ pub struct TripWithUserAndType { } pub struct TripUpdate<'a> { - pub cox: &'a CoxUser, + pub cox: &'a SteeringUser, pub trip: &'a Trip, pub max_people: i32, pub notes: Option<&'a str>, @@ -62,7 +62,7 @@ impl TripWithUserAndType { impl Trip { /// Cox decides to create own trip. - pub async fn new_own(db: &SqlitePool, cox: &CoxUser, trip_details: TripDetails) { + pub async fn new_own(db: &SqlitePool, cox: &SteeringUser, trip_details: TripDetails) { let _ = sqlx::query!( "INSERT INTO trip (cox_id, trip_details_id) VALUES(?, ?)", cox.id, @@ -207,7 +207,7 @@ WHERE trip.id=? /// Cox decides to help in a event. pub async fn new_join( db: &SqlitePool, - cox: &CoxUser, + cox: &SteeringUser, event: &Event, ) -> Result<(), CoxHelpError> { if event.is_rower_registered(db, cox).await { @@ -360,7 +360,7 @@ WHERE day=? pub async fn delete_by_planned_event( db: &SqlitePool, - cox: &CoxUser, + cox: &SteeringUser, event: &Event, ) -> Result<(), TripHelpDeleteError> { if event.trip_details(db).await.is_locked { @@ -387,7 +387,7 @@ WHERE day=? pub(crate) async fn delete( &self, db: &SqlitePool, - user: &CoxUser, + user: &SteeringUser, ) -> Result<(), TripDeleteError> { let registered_rower = Registration::all_rower(db, self.trip_details_id.unwrap()).await; if !registered_rower.is_empty() { @@ -473,7 +473,7 @@ mod test { event::Event, trip::{self, TripDeleteError}, tripdetails::TripDetails, - user::{CoxUser, User}, + user::{SteeringUser, User}, usertrip::UserTrip, }, testdb, @@ -488,7 +488,7 @@ mod test { fn test_new_own() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) @@ -515,7 +515,7 @@ mod test { fn test_new_succ_join() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox2".into()).await.unwrap(), ) @@ -531,7 +531,7 @@ mod test { fn test_new_failed_join_already_cox() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox2".into()).await.unwrap(), ) @@ -548,7 +548,7 @@ mod test { fn test_succ_update_own() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) @@ -576,7 +576,7 @@ mod test { fn test_succ_update_own_with_triptype() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) @@ -604,7 +604,7 @@ mod test { fn test_fail_update_own_not_your_trip() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox2".into()).await.unwrap(), ) @@ -629,7 +629,7 @@ mod test { fn test_succ_delete_by_planned_event() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) @@ -652,7 +652,7 @@ mod test { fn test_succ_delete() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) @@ -670,7 +670,7 @@ mod test { fn test_fail_delete_diff_cox() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox2".into()).await.unwrap(), ) @@ -692,7 +692,7 @@ mod test { fn test_fail_delete_someone_registered() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) diff --git a/src/model/user.rs b/src/model/user.rs index 24127a9..466b5ea 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -50,16 +50,20 @@ pub struct UserWithDetails { #[serde(flatten)] pub user: User, pub amount_unread_notifications: i32, + pub allowed_to_steer: bool, pub on_water: bool, pub roles: Vec, } impl UserWithDetails { pub async fn from_user(user: User, db: &SqlitePool) -> Self { + let allowed_to_steer = + user.has_role(db, "cox").await || user.has_role(db, "Bootsführer").await; Self { on_water: user.on_water(db).await, roles: user.roles(db).await, amount_unread_notifications: user.amount_unread_notifications(db).await, + allowed_to_steer, user, } } @@ -1153,7 +1157,7 @@ macro_rules! special_user { } special_user!(TechUser, +"tech"); -special_user!(CoxUser, +"cox"); +special_user!(SteeringUser, +"cox", +"Bootsführer"); special_user!(AdminUser, +"admin"); special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch"); special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied"); diff --git a/src/model/usertrip.rs b/src/model/usertrip.rs index f73a19a..4ea4341 100644 --- a/src/model/usertrip.rs +++ b/src/model/usertrip.rs @@ -5,7 +5,7 @@ use super::{ notification::Notification, trip::{Trip, TripWithUserAndType}, tripdetails::TripDetails, - user::{CoxUser, User}, + user::{SteeringUser, User}, }; use crate::model::tripdetails::{Action, CoxAtTrip::Yes}; @@ -197,7 +197,7 @@ impl UserTrip { let mut add_info = ""; if let Some(trip) = &trip_to_delete { let cox = User::find_by_id(db, trip.cox_id as i32).await.unwrap(); - trip.delete(db, &CoxUser::new(db, cox).await.unwrap()) + trip.delete(db, &SteeringUser::new(db, cox).await.unwrap()) .await .unwrap(); add_info = " Das war die letzte angemeldete Person. Nachdem nun alle Bescheid wissen, wird die Ausfahrt ab sofort nicht mehr angezeigt."; @@ -270,7 +270,7 @@ pub enum UserTripDeleteError { mod test { use crate::{ model::{ - event::Event, trip::Trip, tripdetails::TripDetails, user::CoxUser, + event::Event, trip::Trip, tripdetails::TripDetails, user::SteeringUser, usertrip::UserTripError, }, testdb, @@ -353,7 +353,7 @@ mod test { fn test_fail_create_is_cox_planned_event() { let pool = testdb!(); - let cox = CoxUser::new( + let cox = SteeringUser::new( &pool, User::find_by_name(&pool, "cox".into()).await.unwrap(), ) diff --git a/src/tera/boatdamage.rs b/src/tera/boatdamage.rs index 246e5c6..ec80954 100644 --- a/src/tera/boatdamage.rs +++ b/src/tera/boatdamage.rs @@ -13,7 +13,7 @@ use crate::{ model::{ boat::Boat, boatdamage::{BoatDamage, BoatDamageFixed, BoatDamageToAdd, BoatDamageVerified}, - user::{CoxUser, DonauLinzUser, TechUser, User, UserWithDetails}, + user::{DonauLinzUser, SteeringUser, TechUser, User, UserWithDetails}, }, tera::log::KioskCookie, }; @@ -133,7 +133,7 @@ async fn fixed<'r>( db: &State, data: Form>, boatdamage_id: i32, - coxuser: CoxUser, + coxuser: SteeringUser, ) -> Flash { let boatdamage = BoatDamage::find_by_id(db, boatdamage_id).await.unwrap(); //TODO: Fix let boatdamage_fixed = BoatDamageFixed { diff --git a/src/tera/cox.rs b/src/tera/cox.rs index 3166fc6..dbee671 100644 --- a/src/tera/cox.rs +++ b/src/tera/cox.rs @@ -11,14 +11,14 @@ use crate::model::{ log::Log, trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError}, tripdetails::{TripDetails, TripDetailsToAdd}, - user::{AllowedToUpdateTripToAlwaysBeShownUser, CoxUser}, + user::{AllowedToUpdateTripToAlwaysBeShownUser, SteeringUser}, }; #[post("/trip", data = "")] async fn create( db: &State, data: Form>, - cox: CoxUser, + cox: SteeringUser, ) -> Flash { let trip_details_id = TripDetails::create(db, data.into_inner()).await; let trip_details = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); //Okay, bc just @@ -50,7 +50,7 @@ async fn update( db: &State, data: Form>, trip_id: i64, - cox: CoxUser, + cox: SteeringUser, ) -> Flash { if let Some(trip) = Trip::find_by_id(db, trip_id).await { let update = trip::TripUpdate { @@ -96,7 +96,7 @@ async fn toggle_always_show( } #[get("/join/")] -async fn join(db: &State, planned_event_id: i64, cox: CoxUser) -> Flash { +async fn join(db: &State, planned_event_id: i64, cox: SteeringUser) -> Flash { if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await { match Trip::new_join(db, &cox, &planned_event).await { Ok(_) => { @@ -130,7 +130,7 @@ async fn join(db: &State, planned_event_id: i64, cox: CoxUser) -> Fl } #[get("/remove/trip/")] -async fn remove_trip(db: &State, trip_id: i64, cox: CoxUser) -> Flash { +async fn remove_trip(db: &State, trip_id: i64, cox: SteeringUser) -> Flash { let trip = Trip::find_by_id(db, trip_id).await; match trip { None => Flash::error(Redirect::to("/planned"), "Trip gibt's nicht!"), @@ -151,7 +151,11 @@ async fn remove_trip(db: &State, trip_id: i64, cox: CoxUser) -> Flas } #[get("/remove/")] -async fn remove(db: &State, planned_event_id: i64, cox: CoxUser) -> Flash { +async fn remove( + db: &State, + planned_event_id: i64, + cox: SteeringUser, +) -> Flash { if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await { match Trip::delete_by_planned_event(db, &cox, &planned_event).await { Ok(_) => { diff --git a/templates/boatdamages.html.tera b/templates/boatdamages.html.tera index 5f44fc5..63751d1 100644 --- a/templates/boatdamages.html.tera +++ b/templates/boatdamages.html.tera @@ -56,7 +56,7 @@ {% if boatdamage.fixed_at %} Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }} {% else %} - {% if loggedin_user and "cox" in loggedin_user.roles %} + {% if loggedin_user and loggedin_user.allowed_to_steer %}
diff --git a/templates/includes/buttons.html.tera b/templates/includes/buttons.html.tera index 8e0dd0e..6f70d16 100644 --- a/templates/includes/buttons.html.tera +++ b/templates/includes/buttons.html.tera @@ -1,4 +1,4 @@ -{% if "cox" in loggedin_user.roles %} +{% if loggedin_user.allowed_to_steer %}
{# --- START Add Buttons --- #} - {% if "manage_events" in loggedin_user.roles or "cox" in loggedin_user.roles %} -
+ {% if "manage_events" in loggedin_user.roles or loggedin_user.allowed_to_steer %} + -{% if "cox" in loggedin_user.roles %} +{% if loggedin_user.allowed_to_steer %} {% include "forms/trip" %} {% endif %} {% if "manage_events" in loggedin_user.roles %} From c87baaed0742e01874942b16c2d9f7ca27d9efd5 Mon Sep 17 00:00:00 2001 From: philipp Date: Fri, 25 Oct 2024 18:31:43 +0200 Subject: [PATCH 2/3] add new halfprice for racerowing --- src/model/user.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/model/user.rs b/src/model/user.rs index 466b5ea..a50287d 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -378,7 +378,11 @@ ASKÖ Ruderverein Donau Linz", self.name), return fee; } if self.has_role(db, "Rennrudern").await { - fee.add("Rennruderbeitrag".into(), RENNRUDERBEITRAG); + if self.has_role(db, "half-rennrudern").await { + fee.add("Rennruderbeitrag (1/2 Preis) ".into(), RENNRUDERBEITRAG / 2); + } else { + fee.add("Rennruderbeitrag".into(), RENNRUDERBEITRAG); + } } let amount_boats = self.amount_boats(db).await; From 779e1bbfb9b103ff03e2aa18c63791f15f11eec6 Mon Sep 17 00:00:00 2001 From: philipp Date: Fri, 25 Oct 2024 18:55:08 +0200 Subject: [PATCH 3/3] backend adaptations due to cox change role --- src/model/boat.rs | 6 +++--- src/model/boatdamage.rs | 3 +-- src/model/notification.rs | 26 ++++++++++++++++++++++++++ src/model/tripdetails.rs | 2 +- src/model/user.rs | 26 ++++++++++++++------------ src/tera/mod.rs | 2 -- src/tera/planned.rs | 2 +- 7 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/model/boat.rs b/src/model/boat.rs index e25af7a..4776cf9 100644 --- a/src/model/boat.rs +++ b/src/model/boat.rs @@ -119,7 +119,7 @@ impl Boat { return true; } - user.has_role(db, "cox").await + user.allowed_to_steer(db).await } pub async fn shipmaster_allowed_tx( @@ -135,7 +135,7 @@ impl Boat { return true; } - user.has_role_tx(db, "cox").await + user.allowed_to_steer_tx(db).await } pub async fn is_locked(&self, db: &SqlitePool) -> bool { @@ -260,7 +260,7 @@ ORDER BY if user.has_role(db, "admin").await { return Self::all(db).await; } - let mut boats = if user.has_role(db, "cox").await { + let mut boats = if user.allowed_to_steer(db).await { sqlx::query_as!( Boat, " diff --git a/src/model/boatdamage.rs b/src/model/boatdamage.rs index e7dc017..bcdb377 100644 --- a/src/model/boatdamage.rs +++ b/src/model/boatdamage.rs @@ -136,8 +136,7 @@ ORDER BY created_at DESC .map_err(|e| e.to_string())?; if !was_unusable_before && boat.is_locked(db).await { - let cox = Role::find_by_name(db, "cox").await.unwrap(); - Notification::create_for_role(db, &cox, &format!("Liebe Steuerberechtigte, bitte beachten, dass {} bis auf weiteres aufgrund von Reparaturarbeiten gesperrt ist.", boat.name), "Boot gesperrt", None, None).await; + Notification::create_for_steering_people(db, &format!("Liebe Steuerberechtigte, bitte beachten, dass {} bis auf weiteres aufgrund von Reparaturarbeiten gesperrt ist.", boat.name), "Boot gesperrt", None, None).await; } let technicals = diff --git a/src/model/notification.rs b/src/model/notification.rs index 0b193ae..ae73ad3 100644 --- a/src/model/notification.rs +++ b/src/model/notification.rs @@ -89,6 +89,32 @@ impl Notification { tx.commit().await.unwrap(); } + pub async fn create_for_steering_people_tx( + db: &mut Transaction<'_, Sqlite>, + message: &str, + category: &str, + link: Option<&str>, + action_after_reading: Option<&str>, + ) { + let cox = Role::find_by_name_tx(db, "cox").await.unwrap(); + Self::create_for_role_tx(db, &cox, message, category, link, action_after_reading).await; + let bootsf = Role::find_by_name_tx(db, "Bootsführer").await.unwrap(); + Self::create_for_role_tx(db, &bootsf, message, category, link, action_after_reading).await; + } + + pub async fn create_for_steering_people( + db: &SqlitePool, + message: &str, + category: &str, + link: Option<&str>, + action_after_reading: Option<&str>, + ) { + let cox = Role::find_by_name(db, "cox").await.unwrap(); + Self::create_for_role(db, &cox, message, category, link, action_after_reading).await; + let bootsf = Role::find_by_name(db, "Bootsführer").await.unwrap(); + Self::create_for_role(db, &bootsf, message, category, link, action_after_reading).await; + } + pub async fn for_user(db: &SqlitePool, user: &User) -> Vec { let rows = sqlx::query!( " diff --git a/src/model/tripdetails.rs b/src/model/tripdetails.rs index 1dd59a5..df5204e 100644 --- a/src/model/tripdetails.rs +++ b/src/model/tripdetails.rs @@ -146,7 +146,7 @@ WHERE day = ? AND planned_starting_time = ? // User is a guest, no need to bother. continue; }; - if !user.has_role(db, "cox").await { + if !user.allowed_to_steer(db).await { // User is no cox, no need to bother continue; } diff --git a/src/model/user.rs b/src/model/user.rs index a50287d..abe3487 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -57,8 +57,8 @@ pub struct UserWithDetails { impl UserWithDetails { pub async fn from_user(user: User, db: &SqlitePool) -> Self { - let allowed_to_steer = - user.has_role(db, "cox").await || user.has_role(db, "Bootsführer").await; + let allowed_to_steer = user.allowed_to_steer(db).await; + Self { on_water: user.on_water(db).await, roles: user.roles(db).await, @@ -140,6 +140,14 @@ impl Fee { } impl User { + pub async fn allowed_to_steer(&self, db: &SqlitePool) -> bool { + self.has_role(db, "cox").await || self.has_role(db, "Bootsführer").await + } + + pub async fn allowed_to_steer_tx(&self, db: &mut Transaction<'_, Sqlite>) -> bool { + self.has_role_tx(db, "cox").await || self.has_role_tx(db, "Bootsführer").await + } + pub async fn send_welcome_email(&self, db: &SqlitePool, smtp_pw: &str) -> Result<(), String> { let Some(mail) = &self.mail else { return Err(format!( @@ -239,10 +247,8 @@ ASKÖ Ruderverein Donau Linz", self.name, SCHECKBUCH/100), ).await?; // 2. Notify all coxes - let coxes = Role::find_by_name(db, "cox").await.unwrap(); - Notification::create_for_role( + Notification::create_for_steering_people( db, - &coxes, &format!( "Liebe Steuerberechtigte, {} hat nun ein Scheckbuch. Wie immer, freuen wir uns wenn du uns beim A+F Rudern unterstützt oder selber Ausfahrten ausschreibst. Bitte beachte, dass Scheckbuch-Personen nur Ausfahrten sehen, bei denen 'Scheckbuch-Anmeldungen erlauben' ausgewählt wurde.", self.name @@ -319,10 +325,8 @@ ASKÖ Ruderverein Donau Linz", self.name), ).await?; // 2. Notify all coxes - let coxes = Role::find_by_name(db, "cox").await.unwrap(); - Notification::create_for_role( + Notification::create_for_steering_people( db, - &coxes, &format!( "Liebe Steuerberechtigte, seit {} gibt es ein neues Mitglied: {}", self.member_since_date.clone().unwrap(), @@ -979,7 +983,7 @@ ORDER BY last_access DESC } pub(crate) async fn amount_days_to_show(&self, db: &SqlitePool) -> i64 { - if self.has_role(db, "cox").await { + if self.allowed_to_steer(db).await { let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 12, 31).unwrap(); //Ok, //december //has 31 @@ -1031,10 +1035,8 @@ ORDER BY last_access DESC if let Some(mail) = &self.mail { let _ = self.send_end_mail_scheckbuch(db, mail, smtp_pw).await; } - let coxes = Role::find_by_name_tx(db, "cox").await.unwrap(); - Notification::create_for_role_tx( + Notification::create_for_steering_people_tx( db, - &coxes, &format!( "Liebe Steuerberechtigte, {} hat alle Ausfahrten des Scheckbuchs absolviert. Hoffentlich können wir uns bald über ein neues Mitglied freuen :-)", self.name diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 314483b..363b6ac 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -93,8 +93,6 @@ async fn steering(db: &State, user: User, flash: Option