use std::ops::Deref; use actix::Addr; use actix_web::{HttpResponse, Responder, web}; use askama::Template; use crate::actors::users_actor; use crate::actors::users_actor::UsersActor; use crate::constants::TEMPORARY_PASSWORDS_LEN; use crate::controllers::settings_controller::BaseSettingsPage; use crate::data::client::{Client, ClientID, ClientManager}; use crate::data::current_user::CurrentUser; use crate::data::user::{hash_password, User, UserID}; use crate::utils::string_utils::rand_str; #[derive(Template)] #[template(path = "settings/clients_list.html")] struct ClientsListTemplate { _parent: BaseSettingsPage, clients: Vec, } #[derive(Template)] #[template(path = "settings/users_list.html")] struct UsersListTemplate { _parent: BaseSettingsPage, users: Vec, } #[derive(Template)] #[template(path = "settings/edit_user.html")] struct EditUserTemplate { _parent: BaseSettingsPage, u: User, clients: Vec, } pub async fn clients_route(user: CurrentUser, clients: web::Data) -> impl Responder { HttpResponse::Ok().body(ClientsListTemplate { _parent: BaseSettingsPage::get( "Clients list", &user, None, None, ), clients: clients.cloned(), }.render().unwrap()) } #[derive(serde::Deserialize, Debug)] pub struct UpdateUserQuery { uid: UserID, username: String, first_name: String, last_name: String, email: String, gen_new_password: Option, enabled: Option, admin: Option, grant_type: String, granted_clients: String, } pub async fn users_route(user: CurrentUser, users: web::Data>, update_query: Option>) -> impl Responder { let mut danger = None; let mut success = None; if let Some(update) = update_query { let current_user: Option = users.send(users_actor::FindUserByUsername(update.username.to_string())) .await.unwrap().0; let is_creating = current_user.is_none(); let mut user = current_user.unwrap_or_default(); user.uid = update.0.uid; user.username = update.0.username; user.first_name = update.0.first_name; user.last_name = update.0.last_name; user.email = update.0.email; user.enabled = update.0.enabled.is_some(); user.admin = update.0.admin.is_some(); user.authorized_clients = match update.0.grant_type.as_str() { "all_clients" => None, "custom_clients" => Some(update.0.granted_clients.split(',') .map(|c| ClientID(c.to_string())) .collect::>()), _ => Some(Vec::new()) }; let new_password = match update.0.gen_new_password.is_some() { false => None, true => { let temp_pass = rand_str(TEMPORARY_PASSWORDS_LEN); user.password = hash_password(&temp_pass) .expect("Failed to hash password"); user.need_reset_password = true; Some(temp_pass) } }; let res = users.send(users_actor::UpdateUserRequest(user.clone())).await.unwrap().0; if !res { danger = Some(match is_creating { true => "Failed to create user!", false => "Failed to update user!" }.to_string()) } else { success = Some(match is_creating { true => format!("User {} was successfully updated!", user.full_name()), false => format!("Failed to update {}'s account!", user.full_name()) }.to_string()); if let Some(pass) = new_password { danger = Some(format!("{}'s temporary time password is {}", user.full_name(), pass)); } } } let users = users.send(users_actor::GetAllUsersRequest).await.unwrap().0; HttpResponse::Ok().body(UsersListTemplate { _parent: BaseSettingsPage::get( "Users list", &user, danger, success, ), users, }.render().unwrap()) } pub async fn create_user(user: CurrentUser, clients: web::Data) -> impl Responder { HttpResponse::Ok().body(EditUserTemplate { _parent: BaseSettingsPage::get("Create a new user", user.deref(), None, None), u: Default::default(), clients: clients.cloned(), }.render().unwrap()) }