diff --git a/src/model/user/clubmember.rs b/src/model/user/clubmember.rs index 1fb461e..4219754 100644 --- a/src/model/user/clubmember.rs +++ b/src/model/user/clubmember.rs @@ -72,7 +72,7 @@ impl ClubMemberUser { Notification::create_for_steering_people( db, &format!( - "Liebe Steuerberechtigte, {} war unterstützendes/förderndes Mitglied und ist nun ein neues reguläres Mitglied. 🎉", + "Liebe Steuerberechtigte, {} hat upgegraded und ist nun ein neues reguläres Mitglied. 🎉", self.name, ), "Neues Vereinsmitglied", @@ -106,7 +106,7 @@ impl ClubMemberUser { db, &vorstand, &format!( - "Lieber Vorstnad, {} war aktives/förderndes Mitglied und ist nun ein unterstützendes Mitglied.", + "Lieber Vorstand, der Mitgliedstatus von {} hat sich geändert auf 'Unterstützendes Mitglied'.", self.name, ), "Neues unterstützendes Vereinsmitglied", @@ -141,7 +141,7 @@ impl ClubMemberUser { db, &vorstand, &format!( - "Lieber Vorstnad, {} war aktives/unterstützendes Mitglied und ist nun ein förderndes Mitglied.", + "Lieber Vorstand, der Mitgliedstatus von {} hat sich geändert auf 'Förderndes Mitglied'.", self.name, ), "Neues förderndes Vereinsmitglied", diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index a7dcb1f..6501625 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod foerdernd; pub(crate) mod member; pub(crate) mod regular; pub(crate) mod scheckbuch; +pub(crate) mod schnupperant; 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 new file mode 100644 index 0000000..10d6b5a --- /dev/null +++ b/src/model/user/schnupperant.rs @@ -0,0 +1,242 @@ +use super::foerdernd::FoerderndUser; +use super::regular::RegularUser; +use super::unterstuetzend::UnterstuetzendUser; +use super::{ManageUserUser, User}; +use crate::model::role::Role; +use crate::NonEmptyString; +use crate::{ + model::{mail::Mail, notification::Notification}, + special_user, +}; +use chrono::NaiveDate; +use rocket::async_trait; +use rocket::fs::TempFile; +use sqlx::SqlitePool; + +special_user!(SchnupperantUser, +"schnupperant"); + +impl SchnupperantUser { + async fn set_data_for_clubmember( + &self, + db: &SqlitePool, + changed_by: &ManageUserUser, + member_since: &NaiveDate, + birthdate: &NaiveDate, + phone: NonEmptyString, + address: NonEmptyString, + membership_pdf: &TempFile<'_>, + ) -> Result<(), String> { + self.user.update_birthdate(db, changed_by, birthdate).await; + self.user + .update_member_since(db, changed_by, member_since) + .await; + + self.user.update_phone(db, changed_by, &phone).await; + self.user.update_address(db, changed_by, &address).await; + self.user + .add_membership_pdf(db, changed_by, membership_pdf) + .await?; + + Ok(()) + } + pub(crate) async fn convert_to_regular_user( + self, + db: &SqlitePool, + smtp_pw: &str, + changed_by: &ManageUserUser, + member_since: &NaiveDate, + birthdate: &NaiveDate, + phone: NonEmptyString, + address: NonEmptyString, + membership_pdf: &TempFile<'_>, + ) -> Result<(), String> { + self.set_data_for_clubmember( + db, + changed_by, + member_since, + birthdate, + phone, + address, + membership_pdf, + ) + .await?; + + // Change roles + let regular = Role::find_by_name(db, "Donau Linz").await.unwrap(); + 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, ®ular).await?; + + // Notify + let regular = RegularUser::new(db, &self.user).await.unwrap(); + regular.send_welcome_mail_to_user(db, smtp_pw).await?; + Notification::create_for_steering_people( + db, + &format!( + "Liebe Steuerberechtigte, {} nahm an unserem Schnupperkurs teil und ist nun seit {} ein neues reguläres Mitglied. 🎉", + self.name, + self.member_since_date.clone().unwrap() + ), + "Neues Vereinsmitglied", + None, + None, + ) + .await; + + Ok(()) + } + + pub(crate) async fn convert_to_unterstuetzend_user( + self, + db: &SqlitePool, + smtp_pw: &str, + changed_by: &ManageUserUser, + member_since: &NaiveDate, + birthdate: &NaiveDate, + phone: NonEmptyString, + address: NonEmptyString, + membership_pdf: &TempFile<'_>, + ) -> Result<(), String> { + // Set data + self.set_data_for_clubmember( + db, + changed_by, + member_since, + birthdate, + phone, + address, + membership_pdf, + ) + .await?; + + // Change roles + let unterstuetzend = Role::find_by_name(db, "Unterstützend").await.unwrap(); + 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?; + + let unterstuetzend = UnterstuetzendUser::new(db, &self.user).await.unwrap(); + unterstuetzend + .send_welcome_mail_to_user(db, smtp_pw) + .await?; + if let Some(vorstand) = Role::find_by_name(db, "vorstand").await { + Notification::create_for_role( + db, + &vorstand, + &format!( + "Lieber Vorstand, {} nahm am Schnupperkurs teil und ist nun seit {} es ein neues unterstützendes Mitglied.", + self.name, + self.member_since_date.clone().unwrap() + ), + "Neues unterstützendes Vereinsmitglied", + None, + None, + ) + .await; + } + + Ok(()) + } + + pub(crate) async fn convert_to_foerdernd_user( + self, + db: &SqlitePool, + smtp_pw: &str, + changed_by: &ManageUserUser, + member_since: &NaiveDate, + birthdate: &NaiveDate, + phone: NonEmptyString, + address: NonEmptyString, + membership_pdf: &TempFile<'_>, + ) -> Result<(), String> { + // Set data + self.set_data_for_clubmember( + db, + changed_by, + member_since, + birthdate, + phone, + address, + membership_pdf, + ) + .await?; + + // Change roles + let unterstuetzend = Role::find_by_name(db, "Förderndes Mitglied").await.unwrap(); + 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?; + + let foerdernd = FoerderndUser::new(db, &self.user).await.unwrap(); + foerdernd.send_welcome_mail_to_user(db, smtp_pw).await?; + if let Some(vorstand) = Role::find_by_name(db, "vorstand").await { + Notification::create_for_role( + db, + &vorstand, + &format!( + "Lieber Vorstand, {} nahm am Schnupperkurs teil und ist nun seit {} es ein neues förderndes Mitglied.", + self.name, + self.member_since_date.clone().unwrap() + ), + "Neues förderndes Vereinsmitglied", + None, + None, + ) + .await; + } + + Ok(()) + } + + // TODO: make private + pub(crate) async fn notify( + &self, + db: &SqlitePool, + mail: &str, + smtp_pw: &str, + ) -> Result<(), String> { + self.send_welcome_mail_to_user(db, mail, smtp_pw).await?; + self.notify_coxes_about_new_scheckbuch(db).await; + + Ok(()) + } + + async fn send_welcome_mail_to_user( + &self, + db: &SqlitePool, + mail: &str, + smtp_pw: &str, + ) -> Result<(), String> { + Mail::send_single( + db, + mail, + "ASKÖ Ruderverein Donau Linz | Dein Scheckbuch wartet auf Dich", + format!( +"Hallo {0}, + +es freut uns sehr, dich bei unserem Schnupperkurs willkommen heißen zu dürfen. Detaillierte Informationen folgen noch, ich werde sie dir ein paar Tage vor dem Termin zusenden. + +Riemen- & Dollenbruch, +ASKÖ Ruderverein Donau Linz", self.name), + smtp_pw, + ).await?; + + Ok(()) + } + + async fn notify_coxes_about_new_scheckbuch(&self, db: &SqlitePool) { + if let Some(role) = Role::find_by_name(db, "schnupper-betreuer").await { + Notification::create_for_steering_people( + db, + &format!( + "Lieber Schnupperbetreuer, {} hat zum Schnupperkurz angemeldet.", + self.name + ), + "Neuer Schnupperant", + None, + None, + ) + .await; + } + } +} diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index 77e5695..38e2c61 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -7,9 +7,10 @@ use crate::{ logbook::Logbook, role::Role, user::{ - clubmember::ClubMemberUser, member::Member, scheckbuch::ScheckbuchUser, AdminUser, - AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails, - UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser, + clubmember::ClubMemberUser, member::Member, scheckbuch::ScheckbuchUser, + schnupperant::SchnupperantUser, AdminUser, AllowedToEditPaymentStatusUser, + ManageUserUser, User, UserWithDetails, UserWithMembershipPdf, + UserWithRolesAndMembershipPdf, VorstandUser, }, }, tera::Config, @@ -814,6 +815,125 @@ struct UserAddScheckbuchForm<'r> { // 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, + member_since: String, + birthdate: String, + phone: String, + address: String, + membership_pdf: TempFile<'a>, +} + +#[post("/user//schnupperant-to-regular", data = "")] +async fn schnupperant_to_regular( + db: &State, + data: Form>, + 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 Ok(birthdate) = NaiveDate::parse_from_str(&data.birthdate, "%Y-%m-%d") else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + format!( + "Geburtsdatum {} ist nicht im YYYY-MM-DD Format", + &data.birthdate + ), + ); + }; + let Ok(member_since) = NaiveDate::parse_from_str(&data.member_since, "%Y-%m-%d") else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + format!( + "Beitrittsdatum {} ist nicht im YYYY-MM-DD Format", + &data.birthdate + ), + ); + }; + + let Some(user) = SchnupperantUser::new(db, &user).await else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + "User ist kein Schnupperant", + ); + }; + + let Ok(phone) = data.phone.clone().try_into() else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + "Vereinsmitglied braucht eine Telefonnummer", + ); + }; + let Ok(address) = data.address.clone().try_into() else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + "Vereinsmitglied braucht eine Adresse", + ); + }; + let response = match &*data.membertype { + "regular" => { + user.convert_to_regular_user( + db, + &config.smtp_pw, + &admin, + &member_since, + &birthdate, + phone, + address, + &data.membership_pdf, + ) + .await + } + "unterstuetzend" => { + user.convert_to_unterstuetzend_user( + db, + &config.smtp_pw, + &admin, + &member_since, + &birthdate, + phone, + address, + &data.membership_pdf, + ) + .await + } + "foerdernd" => { + user.convert_to_foerdernd_user( + db, + &config.smtp_pw, + &admin, + &member_since, + &birthdate, + phone, + address, + &data.membership_pdf, + ) + .await + } + _ => { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + "Membertype gibts ned", + ) + } + }; + + match response { + 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), + } +} + #[derive(FromForm, Debug)] pub struct ScheckToRegularForm<'a> { membertype: String, @@ -965,7 +1085,7 @@ async fn change_membertype( "foerdernd" => user.move_to_foerdernd(db, &admin).await, _ => { return Flash::error( - Redirect::to("/admin/user"), + Redirect::to(format!("/admin/user/{{ id }}")), format!("Membertype gibt's ned"), ) } @@ -1009,6 +1129,7 @@ pub fn routes() -> Vec { remove_role, // scheckbook_to_regular, + schnupperant_to_regular, change_membertype, ] }