Merge pull request 'steering-user' (#778) from steering-user into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 10m55s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Successful in 20m3s

Reviewed-on: #778
This commit is contained in:
philipp 2024-10-25 20:14:06 +02:00
commit ab52bf4e96
16 changed files with 100 additions and 63 deletions

View File

@ -119,7 +119,7 @@ impl Boat {
return true; return true;
} }
user.has_role(db, "cox").await user.allowed_to_steer(db).await
} }
pub async fn shipmaster_allowed_tx( pub async fn shipmaster_allowed_tx(
@ -135,7 +135,7 @@ impl Boat {
return true; 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 { pub async fn is_locked(&self, db: &SqlitePool) -> bool {
@ -260,7 +260,7 @@ ORDER BY
if user.has_role(db, "admin").await { if user.has_role(db, "admin").await {
return Self::all(db).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!( sqlx::query_as!(
Boat, Boat,
" "

View File

@ -136,8 +136,7 @@ ORDER BY created_at DESC
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
if !was_unusable_before && boat.is_locked(db).await { if !was_unusable_before && boat.is_locked(db).await {
let cox = Role::find_by_name(db, "cox").await.unwrap(); 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;
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;
} }
let technicals = let technicals =

View File

@ -89,6 +89,32 @@ impl Notification {
tx.commit().await.unwrap(); 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<Self> { pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<Self> {
let rows = sqlx::query!( let rows = sqlx::query!(
" "
@ -195,7 +221,7 @@ mod test {
notification::Notification, notification::Notification,
trip::Trip, trip::Trip,
tripdetails::{TripDetails, TripDetailsToAdd}, tripdetails::{TripDetails, TripDetailsToAdd},
user::{CoxUser, User}, user::{SteeringUser, User},
usertrip::UserTrip, usertrip::UserTrip,
}, },
testdb, testdb,
@ -231,7 +257,7 @@ mod test {
UserTrip::create(&pool, &rower, &trip_details, None) UserTrip::create(&pool, &rower, &trip_details, None)
.await .await
.unwrap(); .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 .await
.unwrap(); .unwrap();
Trip::new_join(&pool, &cox, &event).await.unwrap(); Trip::new_join(&pool, &cox, &event).await.unwrap();

View File

@ -9,7 +9,7 @@ use super::{
notification::Notification, notification::Notification,
tripdetails::TripDetails, tripdetails::TripDetails,
triptype::TripType, triptype::TripType,
user::{CoxUser, User}, user::{SteeringUser, User},
usertrip::UserTrip, usertrip::UserTrip,
}; };
@ -38,7 +38,7 @@ pub struct TripWithUserAndType {
} }
pub struct TripUpdate<'a> { pub struct TripUpdate<'a> {
pub cox: &'a CoxUser, pub cox: &'a SteeringUser,
pub trip: &'a Trip, pub trip: &'a Trip,
pub max_people: i32, pub max_people: i32,
pub notes: Option<&'a str>, pub notes: Option<&'a str>,
@ -62,7 +62,7 @@ impl TripWithUserAndType {
impl Trip { impl Trip {
/// Cox decides to create own 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!( let _ = sqlx::query!(
"INSERT INTO trip (cox_id, trip_details_id) VALUES(?, ?)", "INSERT INTO trip (cox_id, trip_details_id) VALUES(?, ?)",
cox.id, cox.id,
@ -207,7 +207,7 @@ WHERE trip.id=?
/// Cox decides to help in a event. /// Cox decides to help in a event.
pub async fn new_join( pub async fn new_join(
db: &SqlitePool, db: &SqlitePool,
cox: &CoxUser, cox: &SteeringUser,
event: &Event, event: &Event,
) -> Result<(), CoxHelpError> { ) -> Result<(), CoxHelpError> {
if event.is_rower_registered(db, cox).await { if event.is_rower_registered(db, cox).await {
@ -360,7 +360,7 @@ WHERE day=?
pub async fn delete_by_planned_event( pub async fn delete_by_planned_event(
db: &SqlitePool, db: &SqlitePool,
cox: &CoxUser, cox: &SteeringUser,
event: &Event, event: &Event,
) -> Result<(), TripHelpDeleteError> { ) -> Result<(), TripHelpDeleteError> {
if event.trip_details(db).await.is_locked { if event.trip_details(db).await.is_locked {
@ -387,7 +387,7 @@ WHERE day=?
pub(crate) async fn delete( pub(crate) async fn delete(
&self, &self,
db: &SqlitePool, db: &SqlitePool,
user: &CoxUser, user: &SteeringUser,
) -> Result<(), TripDeleteError> { ) -> Result<(), TripDeleteError> {
let registered_rower = Registration::all_rower(db, self.trip_details_id.unwrap()).await; let registered_rower = Registration::all_rower(db, self.trip_details_id.unwrap()).await;
if !registered_rower.is_empty() { if !registered_rower.is_empty() {
@ -473,7 +473,7 @@ mod test {
event::Event, event::Event,
trip::{self, TripDeleteError}, trip::{self, TripDeleteError},
tripdetails::TripDetails, tripdetails::TripDetails,
user::{CoxUser, User}, user::{SteeringUser, User},
usertrip::UserTrip, usertrip::UserTrip,
}, },
testdb, testdb,
@ -488,7 +488,7 @@ mod test {
fn test_new_own() { fn test_new_own() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )
@ -515,7 +515,7 @@ mod test {
fn test_new_succ_join() { fn test_new_succ_join() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox2".into()).await.unwrap(), User::find_by_name(&pool, "cox2".into()).await.unwrap(),
) )
@ -531,7 +531,7 @@ mod test {
fn test_new_failed_join_already_cox() { fn test_new_failed_join_already_cox() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox2".into()).await.unwrap(), User::find_by_name(&pool, "cox2".into()).await.unwrap(),
) )
@ -548,7 +548,7 @@ mod test {
fn test_succ_update_own() { fn test_succ_update_own() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )
@ -576,7 +576,7 @@ mod test {
fn test_succ_update_own_with_triptype() { fn test_succ_update_own_with_triptype() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )
@ -604,7 +604,7 @@ mod test {
fn test_fail_update_own_not_your_trip() { fn test_fail_update_own_not_your_trip() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox2".into()).await.unwrap(), User::find_by_name(&pool, "cox2".into()).await.unwrap(),
) )
@ -629,7 +629,7 @@ mod test {
fn test_succ_delete_by_planned_event() { fn test_succ_delete_by_planned_event() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )
@ -652,7 +652,7 @@ mod test {
fn test_succ_delete() { fn test_succ_delete() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )
@ -670,7 +670,7 @@ mod test {
fn test_fail_delete_diff_cox() { fn test_fail_delete_diff_cox() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox2".into()).await.unwrap(), User::find_by_name(&pool, "cox2".into()).await.unwrap(),
) )
@ -692,7 +692,7 @@ mod test {
fn test_fail_delete_someone_registered() { fn test_fail_delete_someone_registered() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )

View File

@ -146,7 +146,7 @@ WHERE day = ? AND planned_starting_time = ?
// User is a guest, no need to bother. // User is a guest, no need to bother.
continue; continue;
}; };
if !user.has_role(db, "cox").await { if !user.allowed_to_steer(db).await {
// User is no cox, no need to bother // User is no cox, no need to bother
continue; continue;
} }

View File

@ -50,16 +50,20 @@ pub struct UserWithDetails {
#[serde(flatten)] #[serde(flatten)]
pub user: User, pub user: User,
pub amount_unread_notifications: i32, pub amount_unread_notifications: i32,
pub allowed_to_steer: bool,
pub on_water: bool, pub on_water: bool,
pub roles: Vec<String>, pub roles: Vec<String>,
} }
impl UserWithDetails { impl UserWithDetails {
pub async fn from_user(user: User, db: &SqlitePool) -> Self { pub async fn from_user(user: User, db: &SqlitePool) -> Self {
let allowed_to_steer = user.allowed_to_steer(db).await;
Self { Self {
on_water: user.on_water(db).await, on_water: user.on_water(db).await,
roles: user.roles(db).await, roles: user.roles(db).await,
amount_unread_notifications: user.amount_unread_notifications(db).await, amount_unread_notifications: user.amount_unread_notifications(db).await,
allowed_to_steer,
user, user,
} }
} }
@ -136,6 +140,14 @@ impl Fee {
} }
impl User { 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> { pub async fn send_welcome_email(&self, db: &SqlitePool, smtp_pw: &str) -> Result<(), String> {
let Some(mail) = &self.mail else { let Some(mail) = &self.mail else {
return Err(format!( return Err(format!(
@ -235,10 +247,8 @@ ASKÖ Ruderverein Donau Linz", self.name, SCHECKBUCH/100),
).await?; ).await?;
// 2. Notify all coxes // 2. Notify all coxes
let coxes = Role::find_by_name(db, "cox").await.unwrap(); Notification::create_for_steering_people(
Notification::create_for_role(
db, db,
&coxes,
&format!( &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.", "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 self.name
@ -315,10 +325,8 @@ ASKÖ Ruderverein Donau Linz", self.name),
).await?; ).await?;
// 2. Notify all coxes // 2. Notify all coxes
let coxes = Role::find_by_name(db, "cox").await.unwrap(); Notification::create_for_steering_people(
Notification::create_for_role(
db, db,
&coxes,
&format!( &format!(
"Liebe Steuerberechtigte, seit {} gibt es ein neues Mitglied: {}", "Liebe Steuerberechtigte, seit {} gibt es ein neues Mitglied: {}",
self.member_since_date.clone().unwrap(), self.member_since_date.clone().unwrap(),
@ -374,8 +382,12 @@ ASKÖ Ruderverein Donau Linz", self.name),
return fee; return fee;
} }
if self.has_role(db, "Rennrudern").await { if self.has_role(db, "Rennrudern").await {
if self.has_role(db, "half-rennrudern").await {
fee.add("Rennruderbeitrag (1/2 Preis) ".into(), RENNRUDERBEITRAG / 2);
} else {
fee.add("Rennruderbeitrag".into(), RENNRUDERBEITRAG); fee.add("Rennruderbeitrag".into(), RENNRUDERBEITRAG);
} }
}
let amount_boats = self.amount_boats(db).await; let amount_boats = self.amount_boats(db).await;
if amount_boats > 0 { if amount_boats > 0 {
@ -971,7 +983,7 @@ ORDER BY last_access DESC
} }
pub(crate) async fn amount_days_to_show(&self, db: &SqlitePool) -> i64 { 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, let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 12, 31).unwrap(); //Ok,
//december //december
//has 31 //has 31
@ -1023,10 +1035,8 @@ ORDER BY last_access DESC
if let Some(mail) = &self.mail { if let Some(mail) = &self.mail {
let _ = self.send_end_mail_scheckbuch(db, mail, smtp_pw).await; 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_steering_people_tx(
Notification::create_for_role_tx(
db, db,
&coxes,
&format!( &format!(
"Liebe Steuerberechtigte, {} hat alle Ausfahrten des Scheckbuchs absolviert. Hoffentlich können wir uns bald über ein neues Mitglied freuen :-)", "Liebe Steuerberechtigte, {} hat alle Ausfahrten des Scheckbuchs absolviert. Hoffentlich können wir uns bald über ein neues Mitglied freuen :-)",
self.name self.name
@ -1153,7 +1163,7 @@ macro_rules! special_user {
} }
special_user!(TechUser, +"tech"); special_user!(TechUser, +"tech");
special_user!(CoxUser, +"cox"); special_user!(SteeringUser, +"cox", +"Bootsführer");
special_user!(AdminUser, +"admin"); special_user!(AdminUser, +"admin");
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch"); special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch");
special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied"); special_user!(DonauLinzUser, +"Donau Linz", -"Unterstützend", -"Förderndes Mitglied");

View File

@ -5,7 +5,7 @@ use super::{
notification::Notification, notification::Notification,
trip::{Trip, TripWithUserAndType}, trip::{Trip, TripWithUserAndType},
tripdetails::TripDetails, tripdetails::TripDetails,
user::{CoxUser, User}, user::{SteeringUser, User},
}; };
use crate::model::tripdetails::{Action, CoxAtTrip::Yes}; use crate::model::tripdetails::{Action, CoxAtTrip::Yes};
@ -197,7 +197,7 @@ impl UserTrip {
let mut add_info = ""; let mut add_info = "";
if let Some(trip) = &trip_to_delete { if let Some(trip) = &trip_to_delete {
let cox = User::find_by_id(db, trip.cox_id as i32).await.unwrap(); 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 .await
.unwrap(); .unwrap();
add_info = " Das war die letzte angemeldete Person. Nachdem nun alle Bescheid wissen, wird die Ausfahrt ab sofort nicht mehr angezeigt."; 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 { mod test {
use crate::{ use crate::{
model::{ model::{
event::Event, trip::Trip, tripdetails::TripDetails, user::CoxUser, event::Event, trip::Trip, tripdetails::TripDetails, user::SteeringUser,
usertrip::UserTripError, usertrip::UserTripError,
}, },
testdb, testdb,
@ -353,7 +353,7 @@ mod test {
fn test_fail_create_is_cox_planned_event() { fn test_fail_create_is_cox_planned_event() {
let pool = testdb!(); let pool = testdb!();
let cox = CoxUser::new( let cox = SteeringUser::new(
&pool, &pool,
User::find_by_name(&pool, "cox".into()).await.unwrap(), User::find_by_name(&pool, "cox".into()).await.unwrap(),
) )

View File

@ -13,7 +13,7 @@ use crate::{
model::{ model::{
boat::Boat, boat::Boat,
boatdamage::{BoatDamage, BoatDamageFixed, BoatDamageToAdd, BoatDamageVerified}, boatdamage::{BoatDamage, BoatDamageFixed, BoatDamageToAdd, BoatDamageVerified},
user::{CoxUser, DonauLinzUser, TechUser, User, UserWithDetails}, user::{DonauLinzUser, SteeringUser, TechUser, User, UserWithDetails},
}, },
tera::log::KioskCookie, tera::log::KioskCookie,
}; };
@ -133,7 +133,7 @@ async fn fixed<'r>(
db: &State<SqlitePool>, db: &State<SqlitePool>,
data: Form<FormBoatDamageFixed<'r>>, data: Form<FormBoatDamageFixed<'r>>,
boatdamage_id: i32, boatdamage_id: i32,
coxuser: CoxUser, coxuser: SteeringUser,
) -> Flash<Redirect> { ) -> Flash<Redirect> {
let boatdamage = BoatDamage::find_by_id(db, boatdamage_id).await.unwrap(); //TODO: Fix let boatdamage = BoatDamage::find_by_id(db, boatdamage_id).await.unwrap(); //TODO: Fix
let boatdamage_fixed = BoatDamageFixed { let boatdamage_fixed = BoatDamageFixed {

View File

@ -11,14 +11,14 @@ use crate::model::{
log::Log, log::Log,
trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError}, trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError},
tripdetails::{TripDetails, TripDetailsToAdd}, tripdetails::{TripDetails, TripDetailsToAdd},
user::{AllowedToUpdateTripToAlwaysBeShownUser, CoxUser}, user::{AllowedToUpdateTripToAlwaysBeShownUser, SteeringUser},
}; };
#[post("/trip", data = "<data>")] #[post("/trip", data = "<data>")]
async fn create( async fn create(
db: &State<SqlitePool>, db: &State<SqlitePool>,
data: Form<TripDetailsToAdd<'_>>, data: Form<TripDetailsToAdd<'_>>,
cox: CoxUser, cox: SteeringUser,
) -> Flash<Redirect> { ) -> Flash<Redirect> {
let trip_details_id = TripDetails::create(db, data.into_inner()).await; 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 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<SqlitePool>, db: &State<SqlitePool>,
data: Form<EditTripForm<'_>>, data: Form<EditTripForm<'_>>,
trip_id: i64, trip_id: i64,
cox: CoxUser, cox: SteeringUser,
) -> 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 {
let update = trip::TripUpdate { let update = trip::TripUpdate {
@ -96,7 +96,7 @@ async fn toggle_always_show(
} }
#[get("/join/<planned_event_id>")] #[get("/join/<planned_event_id>")]
async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) -> Flash<Redirect> { async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: SteeringUser) -> Flash<Redirect> {
if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await { if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await {
match Trip::new_join(db, &cox, &planned_event).await { match Trip::new_join(db, &cox, &planned_event).await {
Ok(_) => { Ok(_) => {
@ -130,7 +130,7 @@ async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) -> Fl
} }
#[get("/remove/trip/<trip_id>")] #[get("/remove/trip/<trip_id>")]
async fn remove_trip(db: &State<SqlitePool>, trip_id: i64, cox: CoxUser) -> Flash<Redirect> { async fn remove_trip(db: &State<SqlitePool>, trip_id: i64, cox: SteeringUser) -> Flash<Redirect> {
let trip = Trip::find_by_id(db, trip_id).await; let trip = Trip::find_by_id(db, trip_id).await;
match trip { match trip {
None => Flash::error(Redirect::to("/planned"), "Trip gibt's nicht!"), None => Flash::error(Redirect::to("/planned"), "Trip gibt's nicht!"),
@ -151,7 +151,11 @@ async fn remove_trip(db: &State<SqlitePool>, trip_id: i64, cox: CoxUser) -> Flas
} }
#[get("/remove/<planned_event_id>")] #[get("/remove/<planned_event_id>")]
async fn remove(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) -> Flash<Redirect> { async fn remove(
db: &State<SqlitePool>,
planned_event_id: i64,
cox: SteeringUser,
) -> Flash<Redirect> {
if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await { 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 { match Trip::delete_by_planned_event(db, &cox, &planned_event).await {
Ok(_) => { Ok(_) => {

View File

@ -93,8 +93,6 @@ async fn steering(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage
User::all_with_role(db, &Role::find_by_name(db, "Bootsführer").await.unwrap()).await; User::all_with_role(db, &Role::find_by_name(db, "Bootsführer").await.unwrap()).await;
let mut coxes = User::all_with_role(db, &Role::find_by_name(db, "cox").await.unwrap()).await; let mut coxes = User::all_with_role(db, &Role::find_by_name(db, "cox").await.unwrap()).await;
coxes.retain(|user| !bootskundige.contains(user)); // Remove bootskundige from coxes list
coxes.retain(|user| user.name != "Externe Steuerperson"); coxes.retain(|user| user.name != "Externe Steuerperson");
context.insert("coxes", &coxes); context.insert("coxes", &coxes);

View File

@ -29,7 +29,7 @@ async fn index(
let mut context = Context::new(); let mut context = Context::new();
if user.has_role(db, "cox").await || user.has_role(db, "manage_events").await { if user.allowed_to_steer(db).await || user.has_role(db, "manage_events").await {
let triptypes = TripType::all(db).await; let triptypes = TripType::all(db).await;
context.insert("trip_types", &triptypes); context.insert("trip_types", &triptypes);
} }

View File

@ -56,7 +56,7 @@
{% if boatdamage.fixed_at %} {% if boatdamage.fixed_at %}
<small class="block text-gray-600 dark:text-gray-100">Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }}</small> <small class="block text-gray-600 dark:text-gray-100">Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }}</small>
{% else %} {% else %}
{% if loggedin_user and "cox" in loggedin_user.roles %} {% if loggedin_user and loggedin_user.allowed_to_steer %}
<form action="/boatdamage/{{ boatdamage.id }}/fixed" <form action="/boatdamage/{{ boatdamage.id }}/fixed"
method="post" method="post"
class="flex justify-between mt-3"> class="flex justify-between mt-3">

View File

@ -1,4 +1,4 @@
{% if "cox" in loggedin_user.roles %} {% if loggedin_user.allowed_to_steer %}
<div class="sm:col-span-2 lg:col-span-3 grid md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3"> <div class="sm:col-span-2 lg:col-span-3 grid md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3">
<button type="button" <button type="button"
title="Toggle View" title="Toggle View"

View File

@ -93,7 +93,7 @@
<option value="{{ user.id }}" <option value="{{ user.id }}"
{% if sel %}selected{% endif %} {% if sel %}selected{% endif %}
{% if user.on_water %}disabled="disabled"{% endif %} {% if user.on_water %}disabled="disabled"{% endif %}
data-custom-properties='{"is_cox": {{ "cox" in user.roles }}, "is_racing": {{ "Rennrudern" in user.roles }}, "steers": {{ user.id == steering_person_id }}, "cox_on_boat": {{ user.id == cox_on_boat }}, "searchableText": "{{ user.nickname }}"}'> data-custom-properties='{"is_cox": {{ user.allowed_to_steer }}, "is_racing": {{ "Rennrudern" in user.roles }}, "steers": {{ user.id == steering_person_id }}, "cox_on_boat": {{ user.id == cox_on_boat }}, "searchableText": "{{ user.nickname }}"}'>
{{ user.name }} {{ user.name }}
{% if user.on_water %}(am Wasser){% endif %} {% if user.on_water %}(am Wasser){% endif %}
</option> </option>

View File

@ -23,9 +23,9 @@
{% if on_water | length > 0 %} {% if on_water | length > 0 %}
{% for log in on_water %} {% for log in on_water %}
{% if log.shipmaster == loggedin_user.id %} {% if log.shipmaster == loggedin_user.id %}
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones="cox" not in loggedin_user.roles) }} {{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=not loggedin_user.allowed_to_steer) }}
{% elif "Vorstand" in loggedin_user.roles %} {% elif "Vorstand" in loggedin_user.roles %}
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones="cox" not in loggedin_user.roles) }} {{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=not loggedin_user.allowed_to_steer) }}
{% else %} {% else %}
{{ log::show(log=log, state="on_water", only_ones=true) }} {{ log::show(log=log, state="on_water", only_ones=true) }}
{% endif %} {% endif %}

View File

@ -151,7 +151,7 @@
{% endif %} {% endif %}
{# --- END Row Buttons --- #} {# --- END Row Buttons --- #}
{# --- START Cox Buttons --- #} {# --- START Cox Buttons --- #}
{% if "cox" in loggedin_user.roles %} {% if loggedin_user.allowed_to_steer %}
{% set_global cur_user_participates = false %} {% set_global cur_user_participates = false %}
{% for cox in event.cox %} {% for cox in event.cox %}
{% if cox.name == loggedin_user.name %} {% if cox.name == loggedin_user.name %}
@ -421,11 +421,11 @@
{% endif %} {% endif %}
</div> </div>
{# --- START Add Buttons --- #} {# --- 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 %}
<div class="grid {% if "manage_events" in loggedin_user.roles and "cox" in loggedin_user.roles %}grid-cols-2{% endif %} text-center"> <div class="grid {% if "manage_events" in loggedin_user.roles and loggedin_user.allowed_to_steer %}grid-cols-2{% endif %} text-center">
{% if "manage_events" in loggedin_user.roles %} {% if "manage_events" in loggedin_user.roles %}
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Event</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#addEventForm" class="relative inline-block w-full bg-primary-900 hover:bg-primary-950 focus:bg-primary-950 dark:bg-primary-950 text-white py-2 text-sm font-semibold <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Event</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#addEventForm" class="relative inline-block w-full bg-primary-900 hover:bg-primary-950 focus:bg-primary-950 dark:bg-primary-950 text-white py-2 text-sm font-semibold
{% if "cox" in loggedin_user.roles %} {% if loggedin_user.allowed_to_steer %}
rounded-bl-md rounded-bl-md
{% else %} {% else %}
rounded-b-md rounded-b-md
@ -435,7 +435,7 @@
Event Event
</a> </a>
{% endif %} {% endif %}
{% if "cox" in loggedin_user.roles %} {% if loggedin_user.allowed_to_steer %}
<a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Ausfahrt</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#sidebarForm" class="relative inline-block w-full py-2 text-primary-900 hover:text-primary-950 dark:bg-primary-600 dark:text-white dark:hover:bg-primary-500 dark:hover:text-white focus:text-primary-950 text-sm font-semibold bg-gray-100 hover:bg-gray-200 focus:bg-gray-200 <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Ausfahrt</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#sidebarForm" class="relative inline-block w-full py-2 text-primary-900 hover:text-primary-950 dark:bg-primary-600 dark:text-white dark:hover:bg-primary-500 dark:hover:text-white focus:text-primary-950 text-sm font-semibold bg-gray-100 hover:bg-gray-200 focus:bg-gray-200
{% if "manage_events" in loggedin_user.roles %} {% if "manage_events" in loggedin_user.roles %}
rounded-br-md rounded-br-md
@ -454,7 +454,7 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
{% if "cox" in loggedin_user.roles %} {% if loggedin_user.allowed_to_steer %}
{% include "forms/trip" %} {% include "forms/trip" %}
{% endif %} {% endif %}
{% if "manage_events" in loggedin_user.roles %} {% if "manage_events" in loggedin_user.roles %}