Merge pull request 'steering-user' (#777) from steering-user into staging
All checks were successful
CI/CD Pipeline / test (push) Successful in 10m42s
CI/CD Pipeline / deploy-staging (push) Successful in 5m14s
CI/CD Pipeline / deploy-main (push) Has been skipped

Reviewed-on: #777
This commit is contained in:
2024-10-25 19:06:12 +02:00
16 changed files with 100 additions and 63 deletions

View File

@ -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,
"

View File

@ -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 =

View File

@ -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<Self> {
let rows = sqlx::query!(
"
@ -195,7 +221,7 @@ mod test {
notification::Notification,
trip::Trip,
tripdetails::{TripDetails, TripDetailsToAdd},
user::{CoxUser, User},
user::{SteeringUser, User},
usertrip::UserTrip,
},
testdb,
@ -231,7 +257,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();

View File

@ -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(),
)

View File

@ -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;
}

View File

@ -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<String>,
}
impl UserWithDetails {
pub async fn from_user(user: User, db: &SqlitePool) -> Self {
let allowed_to_steer = user.allowed_to_steer(db).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,
}
}
@ -136,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!(
@ -235,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
@ -315,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(),
@ -374,7 +382,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;
@ -974,7 +986,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
@ -1026,10 +1038,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
@ -1156,7 +1166,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");

View File

@ -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(),
)