use std::collections::HashMap; use crate::model::{ family::Family, role::Role, user::{AdminUser, User, UserWithRoles, VorstandUser}, }; use futures::future::join_all; use rocket::{ form::Form, get, post, request::FlashMessage, response::{Flash, Redirect}, routes, FromForm, Route, State, }; use rocket_dyn_templates::{tera::Context, Template}; use sqlx::SqlitePool; #[get("/user")] async fn index( db: &State, user: VorstandUser, flash: Option>, ) -> Template { let user_futures: Vec<_> = User::all(db) .await .into_iter() .map(|u| async move { UserWithRoles::from_user(u, db).await }) .collect(); let user: User = user.into(); let allowed_to_edit = user.has_role(db, "admin").await; let users: Vec = join_all(user_futures).await; let roles = Role::all(db).await; let families = Family::all_with_members(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("allowed_to_edit", &allowed_to_edit); context.insert("users", &users); context.insert("roles", &roles); context.insert("families", &families); context.insert("loggedin_user", &UserWithRoles::from_user(user, db).await); Template::render("admin/user/index", context.into_json()) } #[get("/user", rank = 2)] async fn index_admin( db: &State, user: AdminUser, flash: Option>, ) -> Template { let user_futures: Vec<_> = User::all(db) .await .into_iter() .map(|u| async move { UserWithRoles::from_user(u, db).await }) .collect(); let user: User = user.user; let allowed_to_edit = user.has_role(db, "admin").await; let users: Vec = join_all(user_futures).await; let roles = Role::all(db).await; let families = Family::all_with_members(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("allowed_to_edit", &allowed_to_edit); context.insert("users", &users); context.insert("roles", &roles); context.insert("families", &families); context.insert("loggedin_user", &UserWithRoles::from_user(user, db).await); Template::render("admin/user/index", context.into_json()) } #[get("/user/fees")] async fn fees( db: &State, admin: VorstandUser, flash: Option>, ) -> Template { let mut context = Context::new(); let users = User::all_payer_groups(db).await; let mut fees = Vec::new(); for user in users { if let Some(fee) = user.fee(db).await { fees.push(fee); } } context.insert("fees", &fees); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert( "loggedin_user", &UserWithRoles::from_user(admin.into(), db).await, ); Template::render("admin/user/fees", context.into_json()) } #[get("/user/fees/paid?")] async fn fees_paid( db: &State, _admin: AdminUser, user_ids: Vec, ) -> Flash { let mut res = String::new(); for user_id in user_ids { let user = User::find_by_id(db, user_id).await.unwrap(); res.push_str(&format!("{} + ", user.name)); if user.has_role(db, "paid").await { user.remove_role(db, &Role::find_by_name(db, "paid").await.unwrap()) .await; } else { user.add_role(db, &Role::find_by_name(db, "paid").await.unwrap()) .await; } } res.truncate(res.len() - 3); // remove ' + ' from the end Flash::success( Redirect::to("/admin/user/fees"), format!("Zahlungsstatus von {} erfolgreich geändert", res), ) } #[get("/user//reset-pw")] async fn resetpw(db: &State, _admin: AdminUser, user: i32) -> Flash { let user = User::find_by_id(db, user).await; match user { Some(user) => { user.reset_pw(db).await; Flash::success( Redirect::to("/admin/user"), format!("Passwort von {} zurückgesetzt", user.name), ) } None => Flash::error(Redirect::to("/admin/user"), "User does not exist"), } } #[get("/user//delete")] async fn delete(db: &State, _admin: AdminUser, user: i32) -> Flash { let user = User::find_by_id(db, user).await; match user { Some(user) => { user.delete(db).await; Flash::success( Redirect::to("/admin/user"), format!("Benutzer {} gelöscht", user.name), ) } None => Flash::error(Redirect::to("/admin/user"), "User does not exist"), } } #[derive(FromForm, Debug)] pub struct UserEditForm { pub(crate) id: i32, pub(crate) dob: Option, pub(crate) weight: Option, pub(crate) sex: Option, pub(crate) roles: HashMap, pub(crate) member_since_date: Option, pub(crate) birthdate: Option, pub(crate) mail: Option, pub(crate) nickname: Option, pub(crate) notes: Option, pub(crate) phone: Option, pub(crate) address: Option, pub(crate) family_id: Option, } #[post("/user", data = "")] async fn update( db: &State, data: Form, _admin: AdminUser, ) -> Flash { let user = User::find_by_id(db, data.id).await; let Some(user) = user else { return Flash::error( Redirect::to("/admin/user"), format!("User with ID {} does not exist!", data.id), ); }; user.update(db, data.into_inner()).await; Flash::success(Redirect::to("/admin/user"), "Successfully updated user") } #[derive(FromForm)] struct UserAddForm<'r> { name: &'r str, } #[post("/user/new", data = "")] async fn create( db: &State, data: Form>, _admin: AdminUser, ) -> Flash { if User::create(db, data.name).await { Flash::success(Redirect::to("/admin/user"), "Successfully created user") } else { Flash::error( Redirect::to("/admin/user"), format!("User {} already exists", data.name), ) } } pub fn routes() -> Vec { routes![ index, index_admin, resetpw, update, create, delete, fees, fees_paid ] }