Merge pull request 'Merge pull request 'nicer sort @ boat reservation' (#1221) from boat-reservation-sort into main' (#1222) from newbie-flag into staging
CI/CD Pipeline / test (push) Successful in 17m53s
CI/CD Pipeline / deploy-staging (push) Successful in 8m26s
CI/CD Pipeline / deploy-main (push) Has been skipped

Reviewed-on: #1222
This commit was merged in pull request #1222.
This commit is contained in:
2026-06-04 19:50:13 +02:00
17 changed files with 114 additions and 28 deletions
+1
View File
@@ -14,6 +14,7 @@ INSERT INTO "role" (name) VALUES ('schriftfuehrer');
INSERT INTO "role" (name) VALUES ('no-einschreibgebuehr'); INSERT INTO "role" (name) VALUES ('no-einschreibgebuehr');
INSERT INTO "role" (name) VALUES ('schnupper-betreuer'); INSERT INTO "role" (name) VALUES ('schnupper-betreuer');
INSERT INTO "role" (name) VALUES ('allow_website_login'); INSERT INTO "role" (name) VALUES ('allow_website_login');
INSERT INTO "role" (name) VALUES ('Vereinsneuling');
INSERT INTO "user" (name, pw) VALUES('admin', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$4P4NCw4Ukhv80/eQYTsarHhnw61JuL1KMx/L9dm82YM'); INSERT INTO "user" (name, pw) VALUES('admin', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$4P4NCw4Ukhv80/eQYTsarHhnw61JuL1KMx/L9dm82YM');
INSERT INTO "user_role" (user_id, role_id) VALUES(1,1); INSERT INTO "user_role" (user_id, role_id) VALUES(1,1);
INSERT INTO "user_role" (user_id, role_id) VALUES(1,2); INSERT INTO "user_role" (user_id, role_id) VALUES(1,2);
+5 -3
View File
@@ -301,8 +301,9 @@ mod test {
always_show: event.always_show, always_show: event.always_show,
is_locked: event.is_locked, is_locked: event.is_locked,
trip_type_id: None, trip_type_id: None,
allow_guests: event.allow_guests,
}; };
event.update(&pool, &user, &cancel_update).await; event.update(&pool, &user, &cancel_update).await.unwrap();
// Rower received notification // Rower received notification
let notifications = Notification::for_user(&pool, &rower).await; let notifications = Notification::for_user(&pool, &rower).await;
@@ -331,13 +332,14 @@ mod test {
always_show: event.always_show, always_show: event.always_show,
is_locked: event.is_locked, is_locked: event.is_locked,
trip_type_id: None, trip_type_id: None,
allow_guests: event.allow_guests,
}; };
event.update(&pool, &user, &update).await; event.update(&pool, &user, &update).await.unwrap();
assert!(Notification::for_user(&pool, &rower).await.is_empty()); assert!(Notification::for_user(&pool, &rower).await.is_empty());
assert!(Notification::for_user(&pool, &cox.user).await.is_empty()); assert!(Notification::for_user(&pool, &cox.user).await.is_empty());
// Cancel event again // Cancel event again
event.update(&pool, &user, &cancel_update).await; event.update(&pool, &user, &cancel_update).await.unwrap();
// Rower is removed if notification is accepted // Rower is removed if notification is accepted
assert!(event.is_rower_registered(&pool, &rower).await); assert!(event.is_rower_registered(&pool, &rower).await);
+21 -6
View File
@@ -48,6 +48,7 @@ pub struct Registration {
pub name: String, pub name: String,
pub registered_at: String, pub registered_at: String,
pub is_guest: bool, pub is_guest: bool,
pub is_newbie: bool,
pub is_real_guest: bool, pub is_real_guest: bool,
} }
@@ -61,7 +62,8 @@ SELECT
user_note, user_note,
user_id, user_id,
(SELECT created_at FROM user WHERE user_trip.user_id = user.id) as registered_at, (SELECT created_at FROM user WHERE user_trip.user_id = user.id) as registered_at,
(SELECT EXISTS (SELECT 1 FROM user_role WHERE user_role.user_id = user_trip.user_id AND user_role.role_id = (SELECT id FROM role WHERE name = 'scheckbuch'))) as is_guest (SELECT EXISTS (SELECT 1 FROM user_role WHERE user_role.user_id = user_trip.user_id AND user_role.role_id = (SELECT id FROM role WHERE name = 'scheckbuch'))) as is_guest,
(SELECT EXISTS (SELECT 1 FROM user_role WHERE user_role.user_id = user_trip.user_id AND user_role.role_id = (SELECT id FROM role WHERE name = 'Vereinsneuling'))) as is_newbie
FROM user_trip WHERE trip_details_id = {} FROM user_trip WHERE trip_details_id = {}
"#,trip_details_id), "#,trip_details_id),
) )
@@ -74,6 +76,7 @@ FROM user_trip WHERE trip_details_id = {}
name: r.get::<Option<String>, usize>(0).or(r.get::<Option<String>, usize>(1)).unwrap(), //Ok, either name or user_note needs to be set name: r.get::<Option<String>, usize>(0).or(r.get::<Option<String>, usize>(1)).unwrap(), //Ok, either name or user_note needs to be set
registered_at: r.get::<String,usize>(3), registered_at: r.get::<String,usize>(3),
is_guest: r.get::<bool, usize>(4), is_guest: r.get::<bool, usize>(4),
is_newbie: r.get::<bool, usize>(5),
is_real_guest: r.get::<Option<i64>, usize>(2).is_none(), is_real_guest: r.get::<Option<i64>, usize>(2).is_none(),
}) })
.collect() .collect()
@@ -98,6 +101,7 @@ FROM trip WHERE planned_event_id = ?
name: r.name.unwrap(), name: r.name.unwrap(),
registered_at: r.registered_at.unwrap(), registered_at: r.registered_at.unwrap(),
is_guest: false, is_guest: false,
is_newbie: false,
is_real_guest: false, is_real_guest: false,
}) })
.collect() //Okay, as Event can only be created with proper DB backing .collect() //Okay, as Event can only be created with proper DB backing
@@ -113,6 +117,7 @@ pub struct EventUpdate<'a> {
pub always_show: bool, pub always_show: bool,
pub is_locked: bool, pub is_locked: bool,
pub trip_type_id: Option<i64>, pub trip_type_id: Option<i64>,
pub allow_guests: bool,
} }
impl EventUpdate<'_> { impl EventUpdate<'_> {
@@ -318,7 +323,17 @@ WHERE trip_details.id=?
} }
//TODO: create unit test //TODO: create unit test
pub async fn update(&self, db: &SqlitePool, user: &EventUser, update: &EventUpdate<'_>) { pub async fn update(&self, db: &SqlitePool, user: &EventUser, update: &EventUpdate<'_>) -> Result<(), String> {
let tripdetails = self.trip_details(db).await;
let was_already_cancelled = tripdetails.cancelled();
if tripdetails.allow_guests && !update.allow_guests {
let rowers = Registration::all_rower(db, self.trip_details_id).await;
if rowers.iter().any(|r| r.is_newbie) {
return Err("Es sind bereits Neulinge angemeldet — 'Neulinge willkommen' kann nicht deaktiviert werden.".into());
}
}
sqlx::query!( sqlx::query!(
"UPDATE planned_event SET name = ?, planned_amount_cox = ? WHERE id = ?", "UPDATE planned_event SET name = ?, planned_amount_cox = ? WHERE id = ?",
update.name, update.name,
@@ -329,16 +344,14 @@ WHERE trip_details.id=?
.await .await
.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
let tripdetails = self.trip_details(db).await;
let was_already_cancelled = tripdetails.cancelled();
sqlx::query!( sqlx::query!(
"UPDATE trip_details SET max_people = ?, notes = ?, always_show = ?, is_locked = ?, trip_type_id = ? WHERE id = ?", "UPDATE trip_details SET max_people = ?, notes = ?, always_show = ?, is_locked = ?, trip_type_id = ?, allow_guests = ? WHERE id = ?",
update.max_people, update.max_people,
update.notes, update.notes,
update.always_show, update.always_show,
update.is_locked, update.is_locked,
update.trip_type_id, update.trip_type_id,
update.allow_guests,
self.trip_details_id self.trip_details_id
) )
.execute(db) .execute(db)
@@ -426,6 +439,8 @@ WHERE trip_details.id=?
.await; .await;
Notification::delete_by_action(db, &format!("remove_trip_by_event:{}", self.id)).await; Notification::delete_by_action(db, &format!("remove_trip_by_event:{}", self.id)).await;
} }
Ok(())
} }
pub async fn delete(&self, db: &SqlitePool) -> Result<(), String> { pub async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
+14 -1
View File
@@ -48,6 +48,7 @@ pub struct TripUpdate<'a> {
pub notes: Option<&'a str>, pub notes: Option<&'a str>,
pub trip_type: Option<i64>, //TODO: Move to `TripType` pub trip_type: Option<i64>, //TODO: Move to `TripType`
pub is_locked: bool, pub is_locked: bool,
pub allow_guests: bool,
} }
impl TripUpdate<'_> { impl TripUpdate<'_> {
@@ -228,6 +229,13 @@ WHERE day=?
let tripdetails = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); let tripdetails = TripDetails::find_by_id(db, trip_details_id).await.unwrap();
let was_already_cancelled = tripdetails.cancelled(); let was_already_cancelled = tripdetails.cancelled();
if tripdetails.allow_guests && !update.allow_guests {
let rowers = Registration::all_rower(db, trip_details_id).await;
if rowers.iter().any(|r| r.is_newbie) {
return Err(TripUpdateError::NeulingAlreadyRegistered);
}
}
let is_locked = if update.cancelled() { let is_locked = if update.cancelled() {
false false
} else { } else {
@@ -235,11 +243,12 @@ WHERE day=?
}; };
sqlx::query!( sqlx::query!(
"UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ?, is_locked = ? WHERE id = ?", "UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ?, is_locked = ?, allow_guests = ? WHERE id = ?",
update.max_people, update.max_people,
update.notes, update.notes,
update.trip_type, update.trip_type,
is_locked, is_locked,
update.allow_guests,
trip_details_id trip_details_id
) )
.execute(db) .execute(db)
@@ -407,6 +416,7 @@ pub enum TripUpdateError {
NotYourTrip, NotYourTrip,
TripDetailsDoesNotExist, TripDetailsDoesNotExist,
TripTypeNotAllowed, TripTypeNotAllowed,
NeulingAlreadyRegistered,
} }
#[cfg(test)] #[cfg(test)]
@@ -540,6 +550,7 @@ mod test {
notes: None, notes: None,
trip_type: None, trip_type: None,
is_locked: false, is_locked: false,
allow_guests: false,
}; };
assert!(Trip::update_own(&pool, &update).await.is_ok()); assert!(Trip::update_own(&pool, &update).await.is_ok());
@@ -568,6 +579,7 @@ mod test {
notes: None, notes: None,
trip_type: Some(1), trip_type: Some(1),
is_locked: false, is_locked: false,
allow_guests: false,
}; };
assert!(Trip::update_own(&pool, &update).await.is_ok()); assert!(Trip::update_own(&pool, &update).await.is_ok());
@@ -596,6 +608,7 @@ mod test {
notes: None, notes: None,
trip_type: None, trip_type: None,
is_locked: false, is_locked: false,
allow_guests: false,
}; };
assert!(Trip::update_own(&pool, &update).await.is_err()); assert!(Trip::update_own(&pool, &update).await.is_err());
assert_eq!(trip.max_people, 1); assert_eq!(trip.max_people, 1);
+11
View File
@@ -528,6 +528,17 @@ impl User {
Ok(()) Ok(())
} }
pub(crate) async fn add_vereinsneuling(
&self,
db: &SqlitePool,
updated_by: &ManageUserUser,
) -> Result<(), String> {
if let Some(vereinsneuling) = Role::find_by_name(db, "Vereinsneuling").await {
self.add_role(db, updated_by, &vereinsneuling).await?;
}
Ok(())
}
pub(crate) async fn remove_membership_pdf(&self, db: &SqlitePool, updated_by: &ManageUserUser) { pub(crate) async fn remove_membership_pdf(&self, db: &SqlitePool, updated_by: &ManageUserUser) {
ActivityBuilder::new(&format!( ActivityBuilder::new(&format!(
"{updated_by} hat die Beitrittserklärung vom Beutzer gelöscht." "{updated_by} hat die Beitrittserklärung vom Beutzer gelöscht."
+10 -5
View File
@@ -112,6 +112,7 @@ impl UserWithDetails {
self.roles.contains(&"Donau Linz".into()) self.roles.contains(&"Donau Linz".into())
|| self.roles.contains(&"Förderndes Mitglied".into()) || self.roles.contains(&"Förderndes Mitglied".into())
|| self.roles.contains(&"scheckbuch".into()) || self.roles.contains(&"scheckbuch".into())
|| self.roles.contains(&"Vereinsneuling".into())
|| self.user.name == "Externe Steuerperson" || self.user.name == "Externe Steuerperson"
} }
} }
@@ -598,18 +599,22 @@ ASKÖ Ruderverein Donau Linz", self.name),
pub async fn get_days(&self, db: &SqlitePool) -> Vec<Day> { pub async fn get_days(&self, db: &SqlitePool) -> Vec<Day> {
let mut days = Vec::new(); let mut days = Vec::new();
for i in 0..self.amount_days_to_show(db).await { let roles = self.roles(db).await;
let is_beginner = roles.contains(&"scheckbuch".to_string())
|| roles.contains(&"Vereinsneuling".to_string());
let days_to_show = self.amount_days_to_show(db).await;
for i in 0..days_to_show {
let date = (Local::now() + chrono::Duration::days(i)).date_naive(); let date = (Local::now() + chrono::Duration::days(i)).date_naive();
if self.has_role(db, "scheckbuch").await { if is_beginner {
days.push(Day::new_guest(db, date, false).await); days.push(Day::new_guest(db, date, false).await);
} else { } else {
days.push(Day::new(db, date, false).await); days.push(Day::new(db, date, false).await);
} }
} }
for date in TripDetails::pinned_days(db, self.amount_days_to_show(db).await - 1).await { for date in TripDetails::pinned_days(db, days_to_show - 1).await {
if self.has_role(db, "scheckbuch").await { if is_beginner {
let day = Day::new_guest(db, date, true).await; let day = Day::new_guest(db, date, true).await;
if !day.events.is_empty() { if !day.events.is_empty() {
days.push(day); days.push(day);
@@ -868,7 +873,7 @@ special_user!(TechUser, +"tech");
special_user!(ErgoUser, +"ergo"); special_user!(ErgoUser, +"ergo");
special_user!(SteeringUser, +"cox", +"Bootsführer"); special_user!(SteeringUser, +"cox", +"Bootsführer");
special_user!(AdminUser, +"admin"); special_user!(AdminUser, +"admin");
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förderndes Mitglied"); special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch", +"Förderndes Mitglied", +"Vereinsneuling");
special_user!(DonauLinzUser, +"Donau Linz", +"Förderndes Mitglied", -"Unterstützend"); // TODO: special_user!(DonauLinzUser, +"Donau Linz", +"Förderndes Mitglied", -"Unterstützend"); // TODO:
// remove -> // remove ->
// RegularUser // RegularUser
+3
View File
@@ -99,6 +99,7 @@ impl NoMembershipUser {
let regular = Role::find_by_name(db, "Donau Linz").await.unwrap(); let regular = Role::find_by_name(db, "Donau Linz").await.unwrap();
self.user.add_role(db, changed_by, &regular).await?; self.user.add_role(db, changed_by, &regular).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let regular = RegularUser::new(db, &self.user).await.unwrap(); let regular = RegularUser::new(db, &self.user).await.unwrap();
regular.send_welcome_mail_to_user(db, smtp_pw).await?; regular.send_welcome_mail_to_user(db, smtp_pw).await?;
@@ -149,6 +150,7 @@ impl NoMembershipUser {
let unterstuetzend = Role::find_by_name(db, "Unterstützend").await.unwrap(); let unterstuetzend = Role::find_by_name(db, "Unterstützend").await.unwrap();
self.user.add_role(db, changed_by, &unterstuetzend).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap(); let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap();
unterstuetzend unterstuetzend
@@ -203,6 +205,7 @@ impl NoMembershipUser {
let foerdernd = Role::find_by_name(db, "Förderndes Mitglied").await.unwrap(); let foerdernd = Role::find_by_name(db, "Förderndes Mitglied").await.unwrap();
self.user.add_role(db, changed_by, &foerdernd).await?; self.user.add_role(db, changed_by, &foerdernd).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap(); let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap();
foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?; foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?;
+1
View File
@@ -47,6 +47,7 @@ pub trait ClubMember {
let user = User::find_by_name(db, name).await.unwrap(); let user = User::find_by_name(db, name).await.unwrap();
user.change_financial(db, created_by, financial).await?; user.change_financial(db, created_by, financial).await?;
user.add_role(db, created_by, role).await?; user.add_role(db, created_by, role).await?;
user.add_vereinsneuling(db, created_by).await?;
ActivityBuilder::new(&format!( ActivityBuilder::new(&format!(
"{created_by} hat Mitglied {user} mit der Rolle {role} angelegt." "{created_by} hat Mitglied {user} mit der Rolle {role} angelegt."
+3
View File
@@ -68,6 +68,7 @@ impl ScheckbuchUser {
let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap(); let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap();
self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.remove_role(db, changed_by, &scheckbook).await?;
self.user.add_role(db, changed_by, &regular).await?; self.user.add_role(db, changed_by, &regular).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
// Notify // Notify
let regular = RegularUser::new(db, &self.user).await.unwrap(); let regular = RegularUser::new(db, &self.user).await.unwrap();
@@ -123,6 +124,7 @@ impl ScheckbuchUser {
let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap(); let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap();
self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.remove_role(db, changed_by, &scheckbook).await?;
self.user.add_role(db, changed_by, &unterstuetzend).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap(); let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap();
unterstuetzend unterstuetzend
@@ -179,6 +181,7 @@ impl ScheckbuchUser {
let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap(); let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap();
self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.remove_role(db, changed_by, &scheckbook).await?;
self.user.add_role(db, changed_by, &unterstuetzend).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap(); let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap();
foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?; foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?;
+3
View File
@@ -75,6 +75,7 @@ impl SchnupperantUser {
let regular = Role::find_by_name(db, "Donau Linz").await.unwrap(); let regular = Role::find_by_name(db, "Donau Linz").await.unwrap();
self.user.add_role(db, changed_by, &regular).await?; self.user.add_role(db, changed_by, &regular).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
let participated_schnupperkurs = Role::find_by_name(db, "participated_schnupperkurs") let participated_schnupperkurs = Role::find_by_name(db, "participated_schnupperkurs")
.await .await
@@ -224,6 +225,7 @@ impl SchnupperantUser {
let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap(); let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap();
self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.remove_role(db, changed_by, &scheckbook).await?;
self.user.add_role(db, changed_by, &unterstuetzend).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await {
self.add_role(db, changed_by, &no_einschreibgebuehr) self.add_role(db, changed_by, &no_einschreibgebuehr)
.await .await
@@ -293,6 +295,7 @@ impl SchnupperantUser {
let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap(); let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap();
self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.remove_role(db, changed_by, &scheckbook).await?;
self.user.add_role(db, changed_by, &unterstuetzend).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?;
self.user.add_vereinsneuling(db, changed_by).await?;
if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await {
self.add_role(db, changed_by, &no_einschreibgebuehr) self.add_role(db, changed_by, &no_einschreibgebuehr)
.await .await
+6 -4
View File
@@ -62,6 +62,7 @@ struct UpdateEventForm<'r> {
always_show: bool, always_show: bool,
is_locked: bool, is_locked: bool,
trip_type: Option<i64>, trip_type: Option<i64>,
allow_guests: bool,
} }
#[put("/planned-event", data = "<data>")] #[put("/planned-event", data = "<data>")]
@@ -78,12 +79,13 @@ async fn update(
always_show: data.always_show, always_show: data.always_show,
is_locked: data.is_locked, is_locked: data.is_locked,
trip_type_id: data.trip_type, trip_type_id: data.trip_type,
allow_guests: data.allow_guests,
}; };
match Event::find_by_id(db, data.id).await { match Event::find_by_id(db, data.id).await {
Some(planned_event) => { Some(planned_event) => match planned_event.update(db, &user, &update).await {
planned_event.update(db, &user, &update).await; Ok(_) => Flash::success(Redirect::to("/planned"), "Event erfolgreich bearbeitet"),
Flash::success(Redirect::to("/planned"), "Event erfolgreich bearbeitet") Err(e) => Flash::error(Redirect::to("/planned"), e),
} },
None => Flash::error(Redirect::to("/planned"), "Planned event id not found"), None => Flash::error(Redirect::to("/planned"), "Planned event id not found"),
} }
} }
+6
View File
@@ -52,6 +52,7 @@ struct EditTripForm<'r> {
notes: Option<&'r str>, notes: Option<&'r str>,
trip_type: Option<i64>, trip_type: Option<i64>,
is_locked: bool, is_locked: bool,
allow_guests: bool,
} }
#[post("/trip/<trip_id>", data = "<data>")] #[post("/trip/<trip_id>", data = "<data>")]
@@ -69,6 +70,7 @@ async fn update(
notes: data.notes, notes: data.notes,
trip_type: data.trip_type, trip_type: data.trip_type,
is_locked: data.is_locked, is_locked: data.is_locked,
allow_guests: data.allow_guests,
}; };
match Trip::update_own(db, &update).await { match Trip::update_own(db, &update).await {
Ok(_) => Flash::success( Ok(_) => Flash::success(
@@ -85,6 +87,10 @@ async fn update(
Err(TripUpdateError::TripDetailsDoesNotExist) => { Err(TripUpdateError::TripDetailsDoesNotExist) => {
Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht") Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht")
} }
Err(TripUpdateError::NeulingAlreadyRegistered) => Flash::error(
Redirect::to("/planned"),
"Es sind bereits Neulinge angemeldet — 'Neulinge willkommen' kann nicht deaktiviert werden.",
),
} }
} else { } else {
Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht") Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht")
+2
View File
@@ -1,3 +1,5 @@
INSERT INTO "role" (name) VALUES ('Vereinsneuling');
-- test user -- test user
INSERT INTO user(name) VALUES('Marie'); INSERT INTO user(name) VALUES('Marie');
INSERT INTO "user_role" (user_id, role_id) VALUES((SELECT id from user where name = 'Marie'),(SELECT id FROM role where name = 'Donau Linz')); INSERT INTO "user_role" (user_id, role_id) VALUES((SELECT id from user where name = 'Marie'),(SELECT id FROM role where name = 'Donau Linz'));
+1 -1
View File
@@ -9,7 +9,7 @@
{{ macros::input(label='Startzeit', name='tripdetails.planned_starting_time', type='time', required=true) }} {{ macros::input(label='Startzeit', name='tripdetails.planned_starting_time', type='time', required=true) }}
{{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', required=true, min='0') }} {{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', required=true, min='0') }}
{{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='tripdetails.max_people', type='number', required=true, min='0') }} {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='tripdetails.max_people', type='number', required=true, min='0') }}
{{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='tripdetails.allow_guests') }} {{ macros::checkbox(label='Neulinge willkommen', name='tripdetails.allow_guests') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show') }} {{ macros::checkbox(label='Immer anzeigen', name='always_show') }}
{{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }} {{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }}
{{ macros::select(label='Typ', data=trip_types, name='tripdetails.trip_type', default='Reguläre Ausfahrt') }} {{ macros::select(label='Typ', data=trip_types, name='tripdetails.trip_type', default='Reguläre Ausfahrt') }}
+1 -1
View File
@@ -4,7 +4,7 @@
<input class="day-js" type="hidden" name="day" value="" /> <input class="day-js" type="hidden" name="day" value="" />
{{ 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='Scheckbuch-Anmeldungen erlauben', name='allow_guests') }} {{ macros::checkbox(label='Neulinge willkommen', name='allow_guests') }}
{{ macros::input(label='Anmerkungen', name='notes', type='input') }} {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
{% if loggedin_user.allowed_to_steer %} {% if loggedin_user.allowed_to_steer %}
{{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }} {{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
+1 -1
View File
@@ -320,7 +320,7 @@ function setChoiceByLabel(choicesInstance, label) {
{% if participants | length > 0 %} {% if participants | length > 0 %}
{% for rower in participants %} {% for rower in participants %}
<div class="relative"> <div class="relative">
{{ rower.name }} {{ rower.name }}{% if rower.is_newbie %} 🐣{% endif %}
{% if rower.is_guest %}<small class="text-gray-600 dark:text-gray-100">(Scheckbuch)</small>{% endif %} {% if rower.is_guest %}<small class="text-gray-600 dark:text-gray-100">(Scheckbuch)</small>{% endif %}
{% if rower.is_real_guest %} {% if rower.is_real_guest %}
<small class="text-gray-600 dark:text-gray-100">(Gast)</small> <small class="text-gray-600 dark:text-gray-100">(Gast)</small>
+23 -4
View File
@@ -55,6 +55,18 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if "Vereinsneuling" in loggedin_user.roles %}
<div class="grid gap-3 sm:col-span-2 lg:col-span-3">
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
<h2 class="h2">Willkommen im Verein!</h2>
<div class="text-sm p-3">
Du siehst aktuell alle Ausfahrten, die für (Vereins-)Neulinge ausgeschrieben sind. Du kannst dich also gerne bei jeder angezeigten Ausfahrt anmelden :-)
<br /><br />
Sobald du einige Ausfahrten hinter dir hast und eine Fahrt nach Ottensheim kein Problem mehr ist, werden dir alle Ausfahrten freigeschalten. Du fühlst dich schon bereit dazu? Dann einfach kurz jemanden vom Vorstand ansprechen oder eine kurze Mail an <a href="mailto:info@rudernlinz.at" class="underline">info@rudernlinz.at</a> schreiben.
</div>
</div>
</div>
{% endif %}
<h1 class="h1 sm:col-span-2 lg:col-span-3">Ausfahrten</h1> <h1 class="h1 sm:col-span-2 lg:col-span-3">Ausfahrten</h1>
{% include "includes/buttons" %} {% include "includes/buttons" %}
{% for day in days %} {% for day in days %}
@@ -154,7 +166,7 @@
" data-body="#event{{ event.trip_details_id }}" class="inline-block link-primary mr-3"> " data-body="#event{{ event.trip_details_id }}" class="inline-block link-primary mr-3">
Details Details
</a> </a>
</div> </div>
<div class="text-right grid gap-2"> <div class="text-right grid gap-2">
{# --- START Row Buttons --- #} {# --- START Row Buttons --- #}
{% set_global cur_user_participates = false %} {% set_global cur_user_participates = false %}
@@ -223,6 +235,9 @@
{{ macros::box(participants=event.rower, empty_seats=event.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=event.trip_details_id, allow_removing="manage_events" in loggedin_user.roles) }} {{ macros::box(participants=event.rower, empty_seats=event.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=event.trip_details_id, allow_removing="manage_events" in loggedin_user.roles) }}
{% endif %} {% endif %}
{# --- END List Rowers --- #} {# --- END List Rowers --- #}
{% if event.allow_guests %}
<div class="text-primary-900 bg-primary-50 text-center p-1 mb-4">Neulinge willkommen</div>
{% endif %}
{% if "manage_events" in loggedin_user.roles %} {% if "manage_events" in loggedin_user.roles %}
<form action="/planned/join/{{ event.trip_details_id }}" method="get" /> <form action="/planned/join/{{ event.trip_details_id }}" method="get" />
{{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }} {{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }}
@@ -231,9 +246,6 @@
type="submit" /> type="submit" />
</form> </form>
{% endif %} {% endif %}
{% if event.allow_guests %}
<div class="text-primary-900 bg-primary-50 text-center p-1 mb-4">Gäste willkommen!</div>
{% endif %}
{% if "manage_events" in loggedin_user.roles %} {% if "manage_events" in loggedin_user.roles %}
{# --- START Edit Form --- #} {# --- START Edit Form --- #}
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md"> <div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
@@ -250,6 +262,7 @@
{{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', value=event.planned_amount_cox, required=true, min='0') }} {{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', value=event.planned_amount_cox, required=true, min='0') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show', id=event.id,checked=event.always_show) }} {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=event.id,checked=event.always_show) }}
{{ macros::checkbox(label='Gesperrt', name='is_locked', id=event.id,checked=event.is_locked) }} {{ macros::checkbox(label='Gesperrt', name='is_locked', id=event.id,checked=event.is_locked) }}
{{ macros::checkbox(label='Neulinge willkommen', name='allow_guests', id=event.id,checked=event.allow_guests) }}
{{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=event.trip_type_id) }} {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=event.trip_type_id) }}
{{ macros::input(label='Anmerkungen', name='notes', type='input', value=event.notes) }} {{ macros::input(label='Anmerkungen', name='notes', type='input', value=event.notes) }}
<input value="Speichern" class="btn btn-primary" type="submit" /> <input value="Speichern" class="btn btn-primary" type="submit" />
@@ -281,6 +294,7 @@
{{ macros::input(label='', name='always_show', type='hidden', value=event.always_show) }} {{ macros::input(label='', name='always_show', type='hidden', value=event.always_show) }}
{{ macros::input(label='', name='is_locked', type='hidden', value=event.is_locked) }} {{ macros::input(label='', name='is_locked', type='hidden', value=event.is_locked) }}
{{ macros::input(label='', name='trip_type', type='hidden', value=event.trip_type_id) }} {{ macros::input(label='', name='trip_type', type='hidden', value=event.trip_type_id) }}
{{ macros::input(label='', name='allow_guests', type='hidden', value=event.allow_guests) }}
<input value="Ausfahrt absagen" class="btn btn-alert" type="submit" /> <input value="Ausfahrt absagen" class="btn btn-alert" type="submit" />
</form> </form>
</div> </div>
@@ -363,6 +377,9 @@
{% else %} {% else %}
{% set amount_cur_rower = trip.rower | length %} {% set amount_cur_rower = trip.rower | length %}
{{ macros::box(participants=trip.rower, empty_seats=trip.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=trip.trip_details_id, allow_removing=loggedin_user.id == trip.cox_id) }} {{ macros::box(participants=trip.rower, empty_seats=trip.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=trip.trip_details_id, allow_removing=loggedin_user.id == trip.cox_id) }}
{% if trip.allow_guests %}
<div class="text-primary-900 bg-primary-50 text-center p-1 mb-4">Neulinge willkommen</div>
{% endif %}
{% if trip.cox_id == loggedin_user.id %} {% if trip.cox_id == loggedin_user.id %}
<form action="/planned/join/{{ trip.trip_details_id }}" method="get" /> <form action="/planned/join/{{ trip.trip_details_id }}" method="get" />
{{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }} {{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }}
@@ -380,6 +397,7 @@
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min=trip.rower | length) }} {{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min=trip.rower | length) }}
{{ 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='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }} {{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }}
{{ macros::checkbox(label='Neulinge willkommen', name='allow_guests', id=trip.id,checked=trip.allow_guests) }}
{% if loggedin_user.allowed_to_steer %} {% if loggedin_user.allowed_to_steer %}
{{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id, only_ergo=not loggedin_user.allowed_to_steer) }} {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id, only_ergo=not loggedin_user.allowed_to_steer) }}
{% else %} {% else %}
@@ -407,6 +425,7 @@
{{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }} {{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }}
{{ macros::input(label='', name='is_locked', type='hidden', value=trip.is_locked) }} {{ macros::input(label='', name='is_locked', type='hidden', value=trip.is_locked) }}
{{ macros::input(label='', name='trip_type', type='hidden', value=trip.trip_type_id) }} {{ macros::input(label='', name='trip_type', type='hidden', value=trip.trip_type_id) }}
{{ macros::input(label='', name='allow_guests', type='hidden', value=trip.allow_guests) }}
<input value="Ausfahrt absagen" class="btn btn-alert" type="submit" /> <input value="Ausfahrt absagen" class="btn btn-alert" type="submit" />
</form> </form>
</div> </div>