diff --git a/src/model/mail.rs b/src/model/mail.rs index 675c8a1..746889f 100644 --- a/src/model/mail.rs +++ b/src/model/mail.rs @@ -79,7 +79,9 @@ impl Mail { .build(); // Send the email - mailer.send(&email).unwrap(); + if let Err(e) = mailer.send(&email) { + Log::create_with_tx(db, format!("Mail nicht versandt: {e:?}")).await; + } Ok(()) } diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index affec60..257551c 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -37,6 +37,7 @@ pub(crate) mod member; pub(crate) mod regular; pub(crate) mod scheckbuch; pub(crate) mod schnupperant; +pub(crate) mod schnupperinterest; pub(crate) mod unterstuetzend; #[derive(FromRow, Serialize, Deserialize, Clone, Debug, Eq, Hash, PartialEq)] diff --git a/src/model/user/schnupperant.rs b/src/model/user/schnupperant.rs index 08b2a07..6ff87b1 100644 --- a/src/model/user/schnupperant.rs +++ b/src/model/user/schnupperant.rs @@ -98,6 +98,12 @@ impl SchnupperantUser { self.user.remove_role(db, changed_by, &schnupperant).await?; self.user.add_role(db, changed_by, &scheckbook).await?; + if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { + self.add_role(db, &changed_by, &no_einschreibgebuehr) + .await + .expect("role doesn't have a group"); + } + let scheckbook = ScheckbuchUser::new(db, &self.user).await.unwrap(); scheckbook.send_welcome_mail_to_user(db, smtp_pw).await?; @@ -115,6 +121,38 @@ impl SchnupperantUser { Ok(()) } + pub(crate) async fn move_to_schnupperinterest( + self, + db: &SqlitePool, + changed_by: &ManageUserUser, + ) -> Result<(), String> { + let schnupperinterest = Role::find_by_name(db, "schnupper-interessierte") + .await + .unwrap(); + let schnupperant = Role::find_by_name(db, "schnupperant").await.unwrap(); + self.user.remove_role(db, changed_by, &schnupperant).await?; + self.user + .add_role(db, changed_by, &schnupperinterest) + .await?; + + if let Some(role) = Role::find_by_name(db, "schnupper-betreuer").await { + Notification::create_for_role( + db, + &role, + &format!( + "Lieber Schnupperbetreuer, {} hat sich vom Schnupperkurs abgemeldet.", + self.name + ), + "Schnupperkurs Abmeldung", + None, + None, + ) + .await; + } + + Ok(()) + } + pub(crate) async fn convert_to_unterstuetzend_user( self, db: &SqlitePool, @@ -143,6 +181,11 @@ impl SchnupperantUser { let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap(); self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?; + if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { + self.add_role(db, &changed_by, &no_einschreibgebuehr) + .await + .expect("role doesn't have a group"); + } let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap(); unterstuetzend @@ -195,6 +238,11 @@ impl SchnupperantUser { let scheckbook = Role::find_by_name(db, "schnupperant").await.unwrap(); self.user.remove_role(db, changed_by, &scheckbook).await?; self.user.add_role(db, changed_by, &unterstuetzend).await?; + if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { + self.add_role(db, &changed_by, &no_einschreibgebuehr) + .await + .expect("role doesn't have a group"); + } let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap(); foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?; @@ -218,14 +266,9 @@ impl SchnupperantUser { } // TODO: make private - pub(crate) async fn notify( - &self, - db: &SqlitePool, - mail: &str, - smtp_pw: &str, - ) -> Result<(), String> { + pub(crate) async fn notify(&self, db: &SqlitePool, smtp_pw: &str) -> Result<(), String> { self.notify_coxes_about_new_scheckbuch(db).await; - self.send_welcome_mail_to_user(db, mail, smtp_pw).await?; + self.send_welcome_mail_to_user(db, smtp_pw).await?; Ok(()) } @@ -233,13 +276,17 @@ impl SchnupperantUser { async fn send_welcome_mail_to_user( &self, db: &SqlitePool, - mail: &str, smtp_pw: &str, ) -> Result<(), String> { + let Some(mail) = &self.mail else { + return Err(format!( + "Couldn't send mail, because user {self} has no mail" + )); + }; Mail::send_single( db, - mail, - "ASKÖ Ruderverein Donau Linz | Dein Scheckbuch wartet auf Dich", + &mail, + "ASKÖ Ruderverein Donau Linz | Anmeldung Schnupperkurs", format!( "Hallo {0}, diff --git a/src/model/user/schnupperinterest.rs b/src/model/user/schnupperinterest.rs new file mode 100644 index 0000000..3fb07d1 --- /dev/null +++ b/src/model/user/schnupperinterest.rs @@ -0,0 +1,103 @@ +use super::scheckbuch::ScheckbuchUser; +use super::schnupperant::SchnupperantUser; +use super::{ManageUserUser, User}; +use crate::model::role::Role; +use crate::{model::notification::Notification, special_user}; +use rocket::async_trait; +use sqlx::SqlitePool; + +special_user!(SchnupperInterestUser, +"schnupper-interessierte"); + +impl SchnupperInterestUser { + pub(crate) async fn move_to_scheckbook( + self, + db: &SqlitePool, + changed_by: &ManageUserUser, + smtp_pw: &str, + ) -> Result<(), String> { + let schnupperinterest = Role::find_by_name(db, "schnupper-interessierte") + .await + .unwrap(); + let scheckbook = Role::find_by_name(db, "scheckbuch").await.unwrap(); + self.user + .remove_role(db, changed_by, &schnupperinterest) + .await?; + self.user.add_role(db, changed_by, &scheckbook).await?; + + let scheckbook = ScheckbuchUser::new(db, &self.user).await.unwrap(); + scheckbook.send_welcome_mail_to_user(db, smtp_pw).await?; + + Notification::create_for_steering_people( + db, + &format!( + "Liebe Steuerberechtigte, {} wollte unseren Schnupperkurs absolviert und 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 + ), + "Neues Scheckbuch", + None, + None + ) + .await; + + Ok(()) + } + + pub(crate) async fn move_to_schnupperant( + self, + db: &SqlitePool, + changed_by: &ManageUserUser, + smtp_pw: &str, + ) -> Result<(), String> { + let schnupperinterest = Role::find_by_name(db, "schnupper-interessierte") + .await + .unwrap(); + let schnupperant = Role::find_by_name(db, "schnupperant").await.unwrap(); + self.user + .remove_role(db, changed_by, &schnupperinterest) + .await?; + self.user.add_role(db, changed_by, &schnupperant).await?; + + let schnupperant = SchnupperantUser::new(db, &self.user).await.unwrap(); + schnupperant.notify(db, smtp_pw).await?; + + if let Some(role) = Role::find_by_name(db, "schnupper-betreuer").await { + Notification::create_for_role( + db, + &role, + &format!( + "Lieber Schnupperbetreuer, {} hat sich zum Schnupperkurs angemeldet.", + self.name + ), + "Neuer Schnupper-Interessierte:r", + None, + None, + ) + .await; + } + + Ok(()) + } + + pub(crate) async fn notify(&self, db: &SqlitePool) -> Result<(), String> { + self.notify_schnupperbetreuer_about_new_interest(db).await; + + Ok(()) + } + + async fn notify_schnupperbetreuer_about_new_interest(&self, db: &SqlitePool) { + if let Some(role) = Role::find_by_name(db, "schnupper-betreuer").await { + Notification::create_for_role( + db, + &role, + &format!( + "Lieber Schnupperbetreuer, {} hat Interesse zum Schnupperkurs bekundet.", + self.name + ), + "Neuer Schnupper-Interessierte:r", + None, + None, + ) + .await; + } + } +} diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index 6c88474..21fbe8c 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -8,9 +8,9 @@ use crate::{ role::Role, user::{ clubmember::ClubMemberUser, member::Member, scheckbuch::ScheckbuchUser, - schnupperant::SchnupperantUser, AdminUser, AllowedToEditPaymentStatusUser, - ManageUserUser, User, UserWithDetails, UserWithMembershipPdf, - UserWithRolesAndMembershipPdf, VorstandUser, + schnupperant::SchnupperantUser, schnupperinterest::SchnupperInterestUser, AdminUser, + AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails, + UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser, }, }, tera::Config, @@ -765,56 +765,6 @@ struct UserAddScheckbuchForm<'r> { // Flash::success(Redirect::to("/admin/user/scheckbuch"), format!("Scheckbuch erfolgreich erstellt. Eine E-Mail in der alles erklärt wird, wurde an {mail} verschickt.")) //} -//#[get("/user/move/schnupperant//to/scheckbuch")] -//async fn schnupper_to_scheckbuch( -// db: &State, -// id: i32, -// admin: SchnupperBetreuerUser, -// config: &State, -//) -> Flash { -// let Some(user) = User::find_by_id(db, id).await else { -// return Flash::error( -// Redirect::to("/admin/schnupper"), -// "user id not found".to_string(), -// ); -// }; -// -// if !user.has_role(db, "schnupperant").await { -// return Flash::error( -// Redirect::to("/admin/schnupper"), -// "kein schnupperant...".to_string(), -// ); -// } -// -// let schnupperant = Role::find_by_name(db, "schnupperant").await.unwrap(); -// let paid = Role::find_by_name(db, "paid").await.unwrap(); -// user.remove_role(db, &schnupperant).await; -// user.remove_role(db, &paid).await; -// -// let scheckbuch = Role::find_by_name(db, "scheckbuch").await.unwrap(); -// user.add_role(db, &scheckbuch) -// .await -// .expect("just removed 'schnupperant' thus can't have a role with that group"); -// -// if let Some(no_einschreibgebuehr) = Role::find_by_name(db, "no-einschreibgebuehr").await { -// user.add_role(db, &no_einschreibgebuehr) -// .await -// .expect("role doesn't have a group"); -// } -// -// user.send_welcome_email(db, &config.smtp_pw).await.unwrap(); -// -// Log::create( -// db, -// format!( -// "{} created new scheckbuch (from schnupperant): {}", -// admin.name, user.name -// ), -// ) -// .await; -// Flash::success(Redirect::to("/admin/schnupper"), format!("Scheckbuch erfolgreich erstellt. Eine E-Mail in der alles erklärt wird, wurde an {} verschickt.", user.mail.unwrap())) -//} - #[derive(FromForm, Debug)] pub struct SchnupperantToRegularForm<'a> { membertype: String, @@ -1130,6 +1080,94 @@ async fn schnupperant_to_scheckbook( } } +#[get("/user//schnupperinterest-to-schnupperant")] +async fn schnupperinterest_to_schnupperant( + db: &State, + admin: ManageUserUser, + config: &State, + id: i32, +) -> Flash { + let Some(user) = User::find_by_id(db, id).await else { + return Flash::error( + Redirect::to("/admin/user"), + format!("User with ID {} does not exist!", id), + ); + }; + + let Some(user) = SchnupperInterestUser::new(&db, &user).await else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + format!("User {user} ist kein Schnupperinteressierter"), + ); + }; + + match user.move_to_schnupperant(db, &admin, &config.smtp_pw).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", id)), + "Mitgliedstyp umgewandelt und Infos versendet", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", id)), e), + } +} + +#[get("/user//schnupperant-to-schnupperinterest")] +async fn schnupperant_to_schnupperinterest( + db: &State, + admin: ManageUserUser, + id: i32, +) -> Flash { + let Some(user) = User::find_by_id(db, id).await else { + return Flash::error( + Redirect::to("/admin/user"), + format!("User with ID {} does not exist!", id), + ); + }; + + let Some(user) = SchnupperantUser::new(&db, &user).await else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + format!("User {user} ist kein Schnupperant"), + ); + }; + + match user.move_to_schnupperinterest(db, &admin).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", id)), + "Mitgliedstyp umgewandelt.", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", id)), e), + } +} +#[get("/user//schnupperinterest-to-scheckbuch")] +async fn schnupperinterest_to_scheckbuch( + db: &State, + admin: ManageUserUser, + config: &State, + id: i32, +) -> Flash { + let Some(user) = User::find_by_id(db, id).await else { + return Flash::error( + Redirect::to("/admin/user"), + format!("User with ID {} does not exist!", id), + ); + }; + + let Some(user) = SchnupperInterestUser::new(&db, &user).await else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + format!("User {user} ist kein Schnupperinteressierter"), + ); + }; + + match user.move_to_scheckbook(db, &admin, &config.smtp_pw).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", id)), + "Mitgliedstyp umgewandelt und Infos versendet", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", id)), e), + } +} + pub fn routes() -> Vec { routes![ index, @@ -1139,7 +1177,6 @@ pub fn routes() -> Vec { update, create, //create_scheckbuch, - //schnupper_to_scheckbuch, delete, fees, fees_paid, @@ -1161,6 +1198,9 @@ pub fn routes() -> Vec { scheckbook_to_regular, schnupperant_to_regular, schnupperant_to_scheckbook, + schnupperinterest_to_schnupperant, + schnupperant_to_schnupperinterest, + schnupperinterest_to_scheckbuch, change_membertype, ] } diff --git a/templates/admin/user/view.html.tera b/templates/admin/user/view.html.tera index 17d6171..9415256 100644 --- a/templates/admin/user/view.html.tera +++ b/templates/admin/user/view.html.tera @@ -4,8 +4,7 @@ {% block content %}
{% if "admin" in loggedin_user.roles or "Vorstand" in loggedin_user.roles %} - ← Userverwaltung + ← Userverwaltung {% endif %}

{{ user.name }}

@@ -82,7 +81,8 @@
{% if user.membership_pdf %} - Beitrittserklärung herunterladen ↓ + Beitrittserklärung herunterladen ↓ {% else %} ⚠️ Aktuell gibt's keine Beitrittserklärung 😢 {% if allowed_to_edit %} @@ -103,8 +103,8 @@
+ onclick="document.getElementById('change-member-type').showModal()" + class="btn btn-dark">Mitgliedsstatus ändern @@ -113,119 +113,158 @@
- -
- -
-
-
- - -
- -
+ +
+ +
+
+
+ + +
+ +
+
-
-
+ {% endif %} {% elif "Scheckbuch" in member %} {% if allowed_to_edit %} -
-
- {% for log in logbook %} - {{ log::show_old(log=log, state="completed", only_ones=false, index=loop.index, allowed_to_edit=false) }} - {% endfor %} +
+
+ {% for log in logbook %} + {{ log::show_old(log=log, state="completed", only_ones=false, index=loop.index, allowed_to_edit=false) }} + {% endfor %} +
+
+ {% endif %} + {% elif "SchnupperInterest" in member %} + {% if allowed_to_edit %} + + + -
{% endif %} {% elif "Schnupperant" in member %} {% if allowed_to_edit %} - - {% endif %} - {% endif %} - - {% if "Scheckbuch" in member or "Schnupperant" in member %} - {% if allowed_to_edit %} -
- -
- -
- -
- {% if "Scheckbuch" in member %} - {% set action = 'scheckbook-to-regular' %} - {% elif "Schnupperant" in member %} - {% set action = 'schnupperant-to-regular' %} - {% endif %} - -
-
- - -
- {{ macros::input(label='Mitglied seit', name='member_since', type="date", value=now() | date(), required=true) }} - {{ macros::input(label='Geburtsdatum', name='birthdate', type="date", value=user.birthdate, required=true) }} - {{ macros::input(label='Telefonnummer', name='phone', type="text", value=user.phone, required=true) }} - {{ macros::input(label='Adresse', name='address', type="text", value=user.address, required=true) }} - {{ macros::input(label='Beitrittserklärung', name='membership_pdf', type="file", accept='application/pdf', required=true) }} - -
-
+ + + -
{% endif %} {% endif %} -
+ {% if "Scheckbuch" in member or "Schnupperant" in member %} + {% if allowed_to_edit %} +
+ +
+ +
+ +
+ {% if "Scheckbuch" in member %} + {% set action = "scheckbook-to-regular" %} + {% elif "Schnupperant" in member %} + {% set action = "schnupperant-to-regular" %} + {% endif %} +
+
+ + +
+ {{ macros::input(label='Mitglied seit', name='member_since', type="date", value=now() | date(), required=true) }} + {{ macros::input(label='Geburtsdatum', name='birthdate', type="date", value=user.birthdate, required=true) }} + {{ macros::input(label='Telefonnummer', name='phone', type="text", value=user.phone, required=true) }} + {{ macros::input(label='Adresse', name='address', type="text", value=user.address, required=true) }} + {{ macros::input(label='Beitrittserklärung', name='membership_pdf', type="file", accept='application/pdf', required=true) }} + +
+
+
+
+ + {% endif %} + {% endif %} +
{% if is_clubmember %}
diff --git a/templates/includes/macros.html.tera b/templates/includes/macros.html.tera index d080232..1b92d40 100644 --- a/templates/includes/macros.html.tera +++ b/templates/includes/macros.html.tera @@ -199,8 +199,8 @@ function setChoiceByLabel(choicesInstance, label) { readonly /> {% if allowed_to_edit %} {% if allowed_to_edit %}