diff --git a/src/model/user/member.rs b/src/model/user/member.rs index 9762fda..9b00a81 100644 --- a/src/model/user/member.rs +++ b/src/model/user/member.rs @@ -14,6 +14,7 @@ pub(crate) enum Member { Regular(User), Foerdernd(User), Unterstuetzend(User), + NoMembership(User), } impl Member { @@ -31,7 +32,7 @@ impl Member { } else if user.has_role(db, "Unterstützend").await { Self::Unterstuetzend(user) } else { - panic!("User {user} has no membership_type!!"); + Self::NoMembership(user) } } diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index 1034337..829fa48 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -34,6 +34,7 @@ mod fee; pub(crate) mod foerdernd; pub(crate) mod member; pub mod merge; +pub(crate) mod nomembership; pub(crate) mod regular; pub(crate) mod scheckbuch; pub(crate) mod schnupperant; diff --git a/src/model/user/nomembership.rs b/src/model/user/nomembership.rs new file mode 100644 index 0000000..3d51544 --- /dev/null +++ b/src/model/user/nomembership.rs @@ -0,0 +1,233 @@ +use super::foerdernd::FoerderndUser; +use super::regular::RegularUser; +use super::scheckbuch::ScheckbuchUser; +use super::unterstuetzend::UnterstuetzendUser; +use super::{ManageUserUser, User}; +use crate::NonEmptyString; +use crate::model::activity::ActivityBuilder; +use crate::model::role::Role; +use crate::model::notification::Notification; +use chrono::NaiveDate; +use rocket::fs::TempFile; +use sqlx::SqlitePool; +use std::fmt::Display; +use std::ops::Deref; + +pub(crate) struct NoMembershipUser { + pub(crate) user: User, +} + +impl Deref for NoMembershipUser { + type Target = User; + fn deref(&self) -> &Self::Target { + &self.user + } +} + +impl Display for NoMembershipUser { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.user.name) + } +} + +impl NoMembershipUser { + pub(crate) async fn new(db: &SqlitePool, user: &User) -> Option { + if ScheckbuchUser::new(db, user).await.is_some() { + return None; + } + if user.has_role(db, "schnupper-interessierte").await { + return None; + } + if user.has_role(db, "schnupperant").await { + return None; + } + if user.has_role(db, "Donau Linz").await { + return None; + } + if user.has_role(db, "Förderndes Mitglied").await { + return None; + } + if user.has_role(db, "Unterstützend").await { + return None; + } + Some(Self { user: user.clone() }) + } + + 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?; + + let regular = Role::find_by_name(db, "Donau Linz").await.unwrap(); + self.user.add_role(db, changed_by, ®ular).await?; + + 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, {} hatte keinen Mitgliedsstatus und ist nun seit {} ein neues reguläres Mitglied. 🎉", + self.name, + member_since + ), + "Neues Vereinsmitglied", + None, + None, + ) + .await; + + ActivityBuilder::new(&format!( + "{changed_by} hat den User ohne Mitgliedsstatus {self} auf ein reguläres Mitglied upgegraded! Die Steuerpersonen wurden via Notification informiert." + )) + .user(&self) + .save(db) + .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> { + self.set_data_for_clubmember( + db, + changed_by, + member_since, + birthdate, + phone, + address, + membership_pdf, + ) + .await?; + + let unterstuetzend = Role::find_by_name(db, "Unterstützend").await.unwrap(); + 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, {} hatte keinen Mitgliedsstatus und ist nun seit {} ein neues unterstützendes Mitglied.", + self.name, + member_since + ), + "Neues unterstützendes Vereinsmitglied", + None, + None, + ) + .await; + } + ActivityBuilder::new(&format!( + "{changed_by} hat den User ohne Mitgliedsstatus {self} auf ein unterstützendes Mitglied upgegraded!" + )) + .user(&self) + .save(db) + .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> { + self.set_data_for_clubmember( + db, + changed_by, + member_since, + birthdate, + phone, + address, + membership_pdf, + ) + .await?; + + let foerdernd = Role::find_by_name(db, "Förderndes Mitglied").await.unwrap(); + self.user.add_role(db, changed_by, &foerdernd).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, {} hatte keinen Mitgliedsstatus und ist nun seit {} ein neues förderndes Mitglied.", + self.name, + member_since + ), + "Neues förderndes Vereinsmitglied", + None, + None, + ) + .await; + } + ActivityBuilder::new(&format!( + "{changed_by} hat den User ohne Mitgliedsstatus {self} auf ein förderndes Mitglied upgegraded!" + )) + .user(&self) + .save(db) + .await; + + Ok(()) + } +} diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index 111c25a..bd1dd60 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -8,8 +8,9 @@ use crate::{ role::Role, user::{ clubmember::ClubMemberUser, foerdernd::FoerderndUser, member::Member, - regular::RegularUser, scheckbuch::ScheckbuchUser, schnupperant::SchnupperantUser, - schnupperinterest::SchnupperInterestUser, unterstuetzend::UnterstuetzendUser, + nomembership::NoMembershipUser, regular::RegularUser, scheckbuch::ScheckbuchUser, + schnupperant::SchnupperantUser, schnupperinterest::SchnupperInterestUser, + unterstuetzend::UnterstuetzendUser, AdminUser, AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser, }, @@ -1141,6 +1142,115 @@ async fn scheckbook_to_regular( } } +#[post("/user//nomembership-to-regular", data = "")] +async fn nomembership_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) = NoMembershipUser::new(db, &user).await else { + return Flash::error( + Redirect::to(format!("/admin/user/{id}")), + "User hat keinen fehlenden Mitgliedsstatus", + ); + }; + + 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 ChangeMembertypeForm { membertype: String, @@ -1554,6 +1664,7 @@ pub fn routes() -> Vec { remove_role, // Moves scheckbook_to_regular, + nomembership_to_regular, schnupperant_to_regular, schnupperant_to_scheckbook, schnupperinterest_to_schnupperant, diff --git a/templates/admin/user/view.html.tera b/templates/admin/user/view.html.tera index b583a77..6fc528a 100644 --- a/templates/admin/user/view.html.tera +++ b/templates/admin/user/view.html.tera @@ -73,6 +73,8 @@ Förderndes Vereinsmitglied {% elif "Unterstuetzend" in member %} Unterstützendes Vereinsmitglied + {% elif "NoMembership" in member %} + ⚠️ Kein Mitgliedsstatus! {% endif %} @@ -229,7 +231,7 @@ {% endif %} {% endif %} - {% if "Scheckbuch" in member or "Schnupperant" in member %} + {% if "Scheckbuch" in member or "Schnupperant" in member or "NoMembership" in member %} {% if allowed_to_edit %}