From c8d5c633d76cbaa983a07f3e0ec1351a13790974 Mon Sep 17 00:00:00 2001 From: Philipp Hofer Date: Wed, 30 Apr 2025 11:06:10 +0200 Subject: [PATCH] be able to update data individually; Fixes #951 --- src/model/mail.rs | 12 +- src/model/role.rs | 8 +- src/model/user/basic.rs | 199 +++++++++++++++ src/model/user/mod.rs | 49 ++-- src/model/user/scheckbuch.rs | 30 +-- src/tera/admin/user.rs | 377 +++++++++++++++++++--------- src/tera/ergo.rs | 89 +++---- templates/admin/user/view.html.tera | 46 +++- 8 files changed, 589 insertions(+), 221 deletions(-) create mode 100644 src/model/user/basic.rs diff --git a/src/model/mail.rs b/src/model/mail.rs index 9879630..675c8a1 100644 --- a/src/model/mail.rs +++ b/src/model/mail.rs @@ -3,7 +3,7 @@ use std::{error::Error, fs}; use lettre::{ message::{header::ContentType, Attachment, MultiPart, SinglePart}, transport::smtp::authentication::Credentials, - Message, SmtpTransport, Transport, + Address, Message, SmtpTransport, Transport, }; use sqlx::{Sqlite, SqlitePool, Transaction}; @@ -374,3 +374,13 @@ Der Vorstand"); } } } + +pub(crate) fn valid_mails(mails: &str) -> bool { + let splitted = mails.split(','); + for single_rec in splitted { + if single_rec.parse::
().is_err() { + return false; + } + } + true +} diff --git a/src/model/role.rs b/src/model/role.rs index c8accad..c055a44 100644 --- a/src/model/role.rs +++ b/src/model/role.rs @@ -1,4 +1,4 @@ -use std::ops::DerefMut; +use std::{fmt::Display, ops::DerefMut}; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; @@ -10,6 +10,12 @@ pub struct Role { pub(crate) cluster: Option, } +impl Display for Role { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} + impl Role { pub async fn all(db: &SqlitePool) -> Vec { sqlx::query_as!(Role, "SELECT id, name, cluster FROM role") diff --git a/src/model/user/basic.rs b/src/model/user/basic.rs new file mode 100644 index 0000000..e4db2b2 --- /dev/null +++ b/src/model/user/basic.rs @@ -0,0 +1,199 @@ +// TODO: put back in `src/model/user/mod.rs` once that is cleaned up + +use super::{AllowedToEditPaymentStatusUser, ManageUserUser, User}; +use crate::model::{log::Log, mail::valid_mails, role::Role}; +use sqlx::SqlitePool; + +impl User { + pub(crate) async fn update_mail( + &self, + db: &SqlitePool, + updated_by: &ManageUserUser, + new_mail: &str, + ) -> Result<(), String> { + let new_mail = new_mail.trim(); + + if !valid_mails(new_mail) { + return Err(format!( + "{new_mail} ist kein gültiges Format für eine Mailadresse" + )); + } + + sqlx::query!("UPDATE user SET mail = ? where id = ?", new_mail, self.id) + .execute(db) + .await + .unwrap(); //Okay, because we can only create a User of a valid id + + let msg = match &self.mail { + Some(old_mail) => format!( + "{updated_by} has changed the mail address of {self} from {old_mail} to {new_mail}" + ), + None => format!("{updated_by} has added a mail address for {self}: {new_mail}"), + }; + Log::create(db, msg).await; + + Ok(()) + } + + pub(crate) async fn update_phone( + &self, + db: &SqlitePool, + updated_by: &ManageUserUser, + new_phone: &str, + ) -> Result<(), String> { + let new_phone = new_phone.trim(); + + let query = if new_phone.is_empty() { + sqlx::query!("UPDATE user SET phone = NULL where id = ?", self.id) + } else { + sqlx::query!("UPDATE user SET phone = ? where id = ?", new_phone, self.id) + }; + query.execute(db).await.unwrap(); //Okay, because we can only create a User of a valid id + + let msg = match &self.phone { + Some(old_phone) if new_phone.is_empty() => format!("{updated_by} has removed the phone number of {self} (old number: {old_phone})"), + Some(old_phone) => format!("{updated_by} has changed the phone number of {self} from {old_phone} to {new_phone}"), + None => format!("{updated_by} has added a phone number for {self}: {new_phone}") + }; + Log::create(db, msg).await; + + Ok(()) + } + + pub(crate) async fn update_nickname( + &self, + db: &SqlitePool, + updated_by: &ManageUserUser, + new_nickname: &str, + ) -> Result<(), String> { + let new_nickname = new_nickname.trim(); + + let query = if new_nickname.is_empty() { + sqlx::query!("UPDATE user SET nickname = NULL where id = ?", self.id) + } else { + sqlx::query!( + "UPDATE user SET nickname = ? where id = ?", + new_nickname, + self.id + ) + }; + query.execute(db).await.unwrap(); //Okay, because we can only create a User of a valid id + + let msg = match &self.nickname { + Some(old_nickname) if new_nickname.is_empty() => format!("{updated_by} has removed the nickname of {self} (old nickname: {old_nickname})"), + Some(old_nickname) => format!("{updated_by} has changed the nickname of {self} from {old_nickname} to {new_nickname}"), + None => format!("{updated_by} has added a nickname for {self}: {new_nickname}") + }; + Log::create(db, msg).await; + + Ok(()) + } + + pub(crate) async fn remove_role( + &self, + db: &SqlitePool, + updated_by: &ManageUserUser, + role: &Role, + ) -> Result<(), String> { + if !self.has_role(db, &role.name).await { + return Err(format!("Kann Rolle {role} von User {self} nicht entfernen, da der User die Rolle gar nicht hat")); + } + + sqlx::query!( + "DELETE FROM user_role WHERE user_id = ? and role_id = ?", + self.id, + role.id + ) + .execute(db) + .await + .unwrap(); + + Log::create( + db, + format!("{updated_by} has removed role {role} from user {self}"), + ) + .await; + + Ok(()) + } + + pub(crate) async fn has_not_paid( + &self, + db: &SqlitePool, + updated_by: &AllowedToEditPaymentStatusUser, + ) { + let paid = Role::find_by_name(db, "paid").await.unwrap(); + + sqlx::query!( + "DELETE FROM user_role WHERE user_id = ? and role_id = ?", + self.id, + paid.id + ) + .execute(db) + .await + .unwrap(); + + Log::create( + db, + format!("{updated_by} has set that user {self} has NOT paid the fee (yet)"), + ) + .await; + } + pub(crate) async fn has_paid( + &self, + db: &SqlitePool, + updated_by: &AllowedToEditPaymentStatusUser, + ) { + let paid = Role::find_by_name(db, "paid").await.unwrap(); + + sqlx::query!( + "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", + self.id, + paid.id + ) + .execute(db) + .await + .expect("paid role has no group"); + + Log::create( + db, + format!("{updated_by} has set that user {self} has paid the fee (yet)"), + ) + .await; + } + + pub(crate) async fn add_role( + &self, + db: &SqlitePool, + updated_by: &ManageUserUser, + role: &Role, + ) -> Result<(), String> { + if self.has_role(db, &role.name).await { + return Err(format!("Kann Rolle {role} von User {self} nicht hinzufügen, da der User die Rolle schon hat")); + } + + sqlx::query!( + "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", + self.id, + role.id + ) + .execute(db) + .await + .map_err(|_| { + format!( + "User already has a role in the cluster '{}'", + role.cluster + .clone() + .expect("db trigger can't activate on empty string") + ) + })?; + + Log::create( + db, + format!("{updated_by} has added role {role} to user {self}"), + ) + .await; + + Ok(()) + } +} diff --git a/src/model/user/mod.rs b/src/model/user/mod.rs index 7da7493..1d0be00 100644 --- a/src/model/user/mod.rs +++ b/src/model/user/mod.rs @@ -1,4 +1,7 @@ -use std::ops::{Deref, DerefMut}; +use std::{ + fmt::Display, + ops::{Deref, DerefMut}, +}; use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; use chrono::{Datelike, Local, NaiveDate}; @@ -29,6 +32,7 @@ use super::{ use crate::{tera::admin::user::UserEditForm, AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD}; use scheckbuch::ScheckbuchUser; +mod basic; mod fee; mod scheckbuch; @@ -53,6 +57,12 @@ pub struct User { pub user_token: String, } +impl Display for User { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct UserWithDetails { #[serde(flatten)] @@ -585,26 +595,6 @@ ORDER BY last_access DESC Ok(()) } - pub async fn add_role(&self, db: &SqlitePool, role: &Role) -> Result<(), String> { - sqlx::query!( - "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", - self.id, - role.id - ) - .execute(db) - .await - .map_err(|_| { - format!( - "User already has a role in the cluster '{}'", - role.cluster - .clone() - .expect("db trigger can't activate on empty string") - ) - })?; - - Ok(()) - } - async fn send_end_mail_scheckbuch( &self, db: &mut Transaction<'_, Sqlite>, @@ -658,17 +648,6 @@ ASKÖ Ruderverein Donau Linz", self.name), Ok(()) } - pub async fn remove_role(&self, db: &SqlitePool, role: &Role) { - sqlx::query!( - "DELETE FROM user_role WHERE user_id = ? and role_id = ?", - self.id, - role.id - ) - .execute(db) - .await - .unwrap(); - } - pub async fn login(db: &SqlitePool, name: &str, pw: &str) -> Result { let name = name.trim().to_lowercase(); // just to make sure... let Some(user) = User::find_by_name(db, &name).await else { @@ -1000,6 +979,12 @@ macro_rules! special_user { } } } + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } + } }; (@check_roles $user:ident, $db:ident, $(+$role:expr),* $(,-$neg_role:expr)*) => { { diff --git a/src/model/user/scheckbuch.rs b/src/model/user/scheckbuch.rs index 3fc04fe..2521eef 100644 --- a/src/model/user/scheckbuch.rs +++ b/src/model/user/scheckbuch.rs @@ -1,7 +1,7 @@ use super::User; use crate::model::user::LoginError; use crate::{ - model::{mail::Mail, notification::Notification, role::Role}, + model::{mail::Mail, notification::Notification}, special_user, SCHECKBUCH, }; use rocket::async_trait; @@ -16,24 +16,24 @@ use std::ops::Deref; special_user!(ScheckbuchUser, +"scheckbuch"); impl ScheckbuchUser { - async fn from(user: User, db: &SqlitePool, mail: &str, smtp_pw: &str) -> Result<(), String> { - // TODO: see when/how to invoke this function (explicit `Neue Person hinzufügen` button? - // Button to transition existing users to scheckbuch? Automatically called when - // `scheckbuch` is newly selected as role? - if user.has_role(db, "scheckbuch").await { - return Err("User is already a scheckbuch".into()); - } + //async fn from(user: User, db: &SqlitePool, mail: &str, smtp_pw: &str) -> Result<(), String> { + // // TODO: see when/how to invoke this function (explicit `Neue Person hinzufügen` button? + // // Button to transition existing users to scheckbuch? Automatically called when + // // `scheckbuch` is newly selected as role? + // if user.has_role(db, "scheckbuch").await { + // return Err("User is already a scheckbuch".into()); + // } - // TODO: do we allow e.g. DonauLinz to scheckbuch? + // // TODO: do we allow e.g. DonauLinz to scheckbuch? - let scheckbuch = Role::find_by_name(db, "scheckbuch").await.unwrap(); - user.add_role(db, &scheckbuch).await.unwrap(); + // let scheckbuch = Role::find_by_name(db, "scheckbuch").await.unwrap(); + // user.add_role(db, &scheckbuch).await.unwrap(); - // TODO: remove all other `membership_type` roles - let new_user = Self::new(db, &user).await.unwrap(); + // // TODO: remove all other `membership_type` roles + // let new_user = Self::new(db, &user).await.unwrap(); - new_user.notify(db, mail, smtp_pw).await - } + // new_user.notify(db, mail, smtp_pw).await + //} pub(crate) async fn notify( &self, diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index aa49ab7..e3424c0 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -7,14 +7,13 @@ use crate::{ logbook::Logbook, role::Role, user::{ - AdminUser, AllowedToEditPaymentStatusUser, ManageUserUser, SchnupperBetreuerUser, User, - UserWithDetails, UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser, + AdminUser, AllowedToEditPaymentStatusUser, ManageUserUser, User, UserWithDetails, + UserWithMembershipPdf, UserWithRolesAndMembershipPdf, VorstandUser, }, }, tera::Config, }; use futures::future::join_all; -use lettre::Address; use rocket::{ form::Form, fs::TempFile, @@ -221,28 +220,9 @@ async fn fees_paid( let user = User::find_by_id(db, user_id).await.unwrap(); res.push_str(&format!("{} + ", user.name)); if user.has_role(db, "paid").await { - Log::create( - db, - format!( - "{} set fees NOT paid for '{}'", - calling_user.user.name, user.name - ), - ) - .await; - user.remove_role(db, &Role::find_by_name(db, "paid").await.unwrap()) - .await; + user.has_not_paid(db, &calling_user).await; } else { - Log::create( - db, - format!( - "{} set fees paid for '{}'", - calling_user.user.name, user.name - ), - ) - .await; - user.add_role(db, &Role::find_by_name(db, "paid").await.unwrap()) - .await - .expect("paid role has no group"); + user.has_paid(db, &calling_user).await; } } @@ -353,6 +333,153 @@ async fn update( } } +#[derive(FromForm, Debug)] +pub struct MailUpdateForm { + mail: String, +} + +#[post("/user//change-mail", data = "")] +async fn update_mail( + db: &State, + data: Form, + 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), + ); + }; + + match user.update_mail(db, &admin, &data.mail).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", user.id)), + "Mailadresse erfolgreich geändert", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e), + } +} + +#[derive(FromForm, Debug)] +pub struct PhoneUpdateForm { + phone: String, +} + +#[post("/user//change-phone", data = "")] +async fn update_phone( + db: &State, + data: Form, + 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), + ); + }; + + match user.update_phone(db, &admin, &data.phone).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", user.id)), + "Telefonnummer erfolgreich geändert", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e), + } +} + +#[derive(FromForm, Debug)] +pub struct NicknameUpdateForm { + nickname: String, +} + +#[post("/user//change-nickname", data = "")] +async fn update_nickname( + db: &State, + data: Form, + 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), + ); + }; + + match user.update_nickname(db, &admin, &data.nickname).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", user.id)), + "Spitzname erfolgreich geändert", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e), + } +} + +#[derive(FromForm, Debug)] +pub struct AddRoleForm { + role_id: i32, +} + +#[post("/user//add-role", data = "")] +async fn add_role( + db: &State, + data: Form, + 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(role) = Role::find_by_id(db, data.role_id).await else { + return Flash::error( + Redirect::to("/admin/user/{user_id}"), + format!("Role with ID {} does not exist!", data.role_id), + ); + }; + + match user.add_role(db, &admin, &role).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", user.id)), + "Rolle erfolgreich hinzugefügt", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e), + } +} + +#[get("/user//remove-role/")] +async fn remove_role( + db: &State, + admin: ManageUserUser, + user_id: i32, + role_id: i32, +) -> Flash { + let Some(user) = User::find_by_id(db, user_id).await else { + return Flash::error( + Redirect::to("/admin/user"), + format!("User with ID {} does not exist!", user_id), + ); + }; + let Some(role) = Role::find_by_id(db, role_id).await else { + return Flash::error( + Redirect::to("/admin/user/{user_id}"), + format!("Role with ID {} does not exist!", role_id), + ); + }; + + match user.remove_role(db, &admin, &role).await { + Ok(_) => Flash::success( + Redirect::to(format!("/admin/user/{}", user.id)), + "Rolle erfolgreich gelöscht", + ), + Err(e) => Flash::error(Redirect::to(format!("/admin/user/{}", user.id)), e), + } +} + #[get("/user//membership")] async fn download_membership_pdf( db: &State, @@ -405,102 +532,102 @@ struct UserAddScheckbuchForm<'r> { mail: &'r str, } -#[post("/user/new/scheckbuch", data = "")] -async fn create_scheckbuch( - db: &State, - data: Form>, - admin: VorstandUser, - config: &State, -) -> Flash { - // 1. Check mail adress - let mail = data.mail.trim(); - if mail.parse::
().is_err() { - return Flash::error( - Redirect::to("/admin/user/scheckbuch"), - "Keine gültige Mailadresse".to_string(), - ); - } +//#[post("/user/new/scheckbuch", data = "")] +//async fn create_scheckbuch( +// db: &State, +// data: Form>, +// admin: VorstandUser, +// config: &State, +//) -> Flash { +// // 1. Check mail adress +// let mail = data.mail.trim(); +// if mail.parse::
().is_err() { +// return Flash::error( +// Redirect::to("/admin/user/scheckbuch"), +// "Keine gültige Mailadresse".to_string(), +// ); +// } +// +// // 2. Check name +// let name = data.name.trim(); +// if User::find_by_name(db, name).await.is_some() { +// return Flash::error( +// Redirect::to("/admin/user/scheckbuch"), +// "Kann kein Scheckbuch erstellen, der Name wird bereits von einem User verwendet" +// .to_string(), +// ); +// } +// +// // 3. Create user +// User::create_with_mail(db, name, mail).await; +// let user = User::find_by_name(db, name).await.unwrap(); +// +// // 4. Add 'scheckbuch' role +// let scheckbuch = Role::find_by_name(db, "scheckbuch").await.unwrap(); +// user.add_role(db, &scheckbuch) +// .await +// .expect("new user has no roles yet"); +// +// // 4. Send welcome mail (+ notification) +// user.send_welcome_email(db, &config.smtp_pw).await.unwrap(); +// +// Log::create( +// db, +// format!("{} created new scheckbuch: {data:?}", admin.name), +// ) +// .await; +// Flash::success(Redirect::to("/admin/user/scheckbuch"), format!("Scheckbuch erfolgreich erstellt. Eine E-Mail in der alles erklärt wird, wurde an {mail} verschickt.")) +//} - // 2. Check name - let name = data.name.trim(); - if User::find_by_name(db, name).await.is_some() { - return Flash::error( - Redirect::to("/admin/user/scheckbuch"), - "Kann kein Scheckbuch erstellen, der Name wird bereits von einem User verwendet" - .to_string(), - ); - } - - // 3. Create user - User::create_with_mail(db, name, mail).await; - let user = User::find_by_name(db, name).await.unwrap(); - - // 4. Add 'scheckbuch' role - let scheckbuch = Role::find_by_name(db, "scheckbuch").await.unwrap(); - user.add_role(db, &scheckbuch) - .await - .expect("new user has no roles yet"); - - // 4. Send welcome mail (+ notification) - user.send_welcome_email(db, &config.smtp_pw).await.unwrap(); - - Log::create( - db, - format!("{} created new scheckbuch: {data:?}", admin.name), - ) - .await; - 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())) -} +//#[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())) +//} pub fn routes() -> Vec { routes![ @@ -510,13 +637,19 @@ pub fn routes() -> Vec { resetpw, update, create, - create_scheckbuch, - schnupper_to_scheckbuch, + //create_scheckbuch, + //schnupper_to_scheckbuch, delete, fees, fees_paid, scheckbuch, download_membership_pdf, - send_welcome_mail + send_welcome_mail, + // + update_mail, + update_phone, + update_nickname, + add_role, + remove_role, ] } diff --git a/src/tera/ergo.rs b/src/tera/ergo.rs index 31b3d0d..68f7588 100644 --- a/src/tera/ergo.rs +++ b/src/tera/ergo.rs @@ -1,6 +1,6 @@ use std::env; -use chrono::{Datelike, Utc}; +use chrono::Utc; use rocket::{ form::Form, fs::TempFile, @@ -145,47 +145,47 @@ pub struct UserAdd { sex: String, } -#[post("/set-data", data = "")] -async fn new_user(db: &State, data: Form, user: User) -> Flash { - if user.has_role(db, "ergo").await { - return Flash::error(Redirect::to("/ergo"), "Du hast deine Daten schon eingegeben. Wenn du sie updaten willst, melde dich bitte bei it@rudernlinz.at"); - } - - // check data - if data.birthyear < 1900 || data.birthyear > chrono::Utc::now().year() - 5 { - return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geburtsjahr..."); - } - if data.weight < 20 || data.weight > 200 { - return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Gewicht..."); - } - if &data.sex != "f" && &data.sex != "m" { - return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geschlecht..."); - } - - // set data - user.update_ergo(db, data.birthyear, data.weight, &data.sex) - .await; - - // inform all other `ergo` users - let ergo = Role::find_by_name(db, "ergo").await.unwrap(); - Notification::create_for_role( - db, - &ergo, - &format!("{} nimmt heuer an der Ergochallenge teil 💪", user.name), - "Ergo Challenge", - None, - None, - ) - .await; - - // add to `ergo` group - user.add_role(db, &ergo).await.unwrap(); - - Flash::success( - Redirect::to("/ergo"), - "Du hast deine Daten erfolgreich eingegeben. Viel Spaß beim Schwitzen :-)", - ) -} +//#[post("/set-data", data = "")] +//async fn new_user(db: &State, data: Form, user: User) -> Flash { +// if user.has_role(db, "ergo").await { +// return Flash::error(Redirect::to("/ergo"), "Du hast deine Daten schon eingegeben. Wenn du sie updaten willst, melde dich bitte bei it@rudernlinz.at"); +// } +// +// // check data +// if data.birthyear < 1900 || data.birthyear > chrono::Utc::now().year() - 5 { +// return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geburtsjahr..."); +// } +// if data.weight < 20 || data.weight > 200 { +// return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Gewicht..."); +// } +// if &data.sex != "f" && &data.sex != "m" { +// return Flash::error(Redirect::to("/ergo"), "Bitte überprüfe dein Geschlecht..."); +// } +// +// // set data +// user.update_ergo(db, data.birthyear, data.weight, &data.sex) +// .await; +// +// // inform all other `ergo` users +// let ergo = Role::find_by_name(db, "ergo").await.unwrap(); +// Notification::create_for_role( +// db, +// &ergo, +// &format!("{} nimmt heuer an der Ergochallenge teil 💪", user.name), +// "Ergo Challenge", +// None, +// None, +// ) +// .await; +// +// // add to `ergo` group +// user.add_role(db, &ergo).await.unwrap(); +// +// Flash::success( +// Redirect::to("/ergo"), +// "Du hast deine Daten erfolgreich eingegeben. Viel Spaß beim Schwitzen :-)", +// ) +//} #[derive(FromForm, Debug)] pub struct ErgoToAdd<'a> { @@ -358,7 +358,10 @@ async fn new_dozen( } pub fn routes() -> Vec { - routes![index, new_thirty, new_dozen, send, reset, update, new_user] + routes![ + index, new_thirty, new_dozen, send, reset, update, + // new_user + ] } #[cfg(test)] diff --git a/templates/admin/user/view.html.tera b/templates/admin/user/view.html.tera index 21c32b1..4a0dc3b 100644 --- a/templates/admin/user/view.html.tera +++ b/templates/admin/user/view.html.tera @@ -16,10 +16,42 @@
    -
  • Mail: {{ user.mail }}
  • -
  • Notizen: {{ user.notes }}
  • -
  • Telefon: {{ user.phone }}
  • -
  • Spitzname: {{ user.nickname }}
  • +
  • + Mail: {{ user.mail }} + {% if allowed_to_edit %} +
    + ✏️ +
    + {{ macros::input(label='Neue Mailadresse', name='mail', type="text", value=user.mail) }} + +
    +
    + {% endif %} +
  • +
  • Notizen: to be replaced with activity :-)
  • +
  • + Telefon: {{ user.phone }} + {% if allowed_to_edit %} +
    + ✏️ +
    + {{ macros::input(label='Neue Telefonnummer', name='phone', type="text", value=user.phone) }} + +
    +
    + {% endif %} +
  • +
  • Spitzname: {{ user.nickname }} + {% if allowed_to_edit %} +
    + ✏️ +
    + {{ macros::input(label='Neuer Spitzname', name='nickname', type="text", value=user.nickname) }} + +
    +
    + {% endif %} +
@@ -40,11 +72,11 @@ {% if allowed_to_edit %}
+ Rolle -
+
- {% for role in roles %} - {% if not role.cluster %}{% endif %} + {% if not role.cluster and role not in user.proper_roles %}{% endif %} {% endfor %}