use std::ops::Deref; use actix::Addr; use actix_web::{web, HttpResponse, Responder}; 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::action_logger::{Action, ActionLogger}; use crate::data::client::{Client, ClientID, ClientManager}; use crate::data::current_user::CurrentUser; use crate::data::user::{GrantedClients, User, UserID}; use crate::utils::string_utils::rand_str; #[derive(Template)] #[template(path = "settings/clients_list.html")] struct ClientsListTemplate { _p: BaseSettingsPage, clients: Vec, } #[derive(Template)] #[template(path = "settings/users_list.html")] struct UsersListTemplate { _p: BaseSettingsPage, users: Vec, } #[derive(Template)] #[template(path = "settings/edit_user.html")] struct EditUserTemplate { _p: BaseSettingsPage, u: User, clients: Vec, } pub async fn clients_route(user: CurrentUser, clients: web::Data) -> impl Responder { HttpResponse::Ok().body( ClientsListTemplate { _p: 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, two_factor_exemption_after_successful_login: Option, admin: Option, grant_type: String, granted_clients: String, two_factor: String, clear_2fa_history: Option, } pub async fn users_route( user: CurrentUser, users: web::Data>, update_query: Option>, logger: ActionLogger, ) -> 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.two_factor_exemption_after_successful_login = update .0 .two_factor_exemption_after_successful_login .is_some(); user.admin = update.0.admin.is_some(); let res = users .send(users_actor::UpdateUserRequest(user.clone())) .await .unwrap(); // Update the list of factors let factors_to_keep = update.0.two_factor.split(';').collect::>(); for factor in &user.two_factor { if !factors_to_keep.contains(&factor.id.0.as_str()) { logger.log(Action::AdminRemoveUserFactor(&user, factor)); users .send(users_actor::Remove2FAFactor( user.uid.clone(), factor.id.clone(), )) .await .unwrap(); } } // Update list of granted clients let granted_clients = match update.0.grant_type.as_str() { "all_clients" => GrantedClients::AllClients, "custom_clients" if !update.0.granted_clients.is_empty() => { GrantedClients::SomeClients( update .0 .granted_clients .split(',') .map(|c| ClientID(c.to_string())) .collect::>(), ) } _ => GrantedClients::NoClient, }; if user.granted_clients() != granted_clients { logger.log(Action::AdminSetNewGrantedClientsList( &user, &granted_clients, )); users .send(users_actor::SetGrantedClients( user.uid.clone(), granted_clients, )) .await .unwrap(); } // Clear user 2FA history if requested if update.0.clear_2fa_history.is_some() { logger.log(Action::AdminClear2FAHistory(&user)); users .send(users_actor::Clear2FALoginHistory(user.uid.clone())) .await .unwrap(); } // If the admin requested it, reset user password let new_password = match update.0.gen_new_password.is_some() { false => None, true => { logger.log(Action::AdminResetUserPassword(&user)); let temp_pass = rand_str(TEMPORARY_PASSWORDS_LEN); users .send(users_actor::ChangePasswordRequest { user_id: user.uid.clone(), new_password: temp_pass.clone(), temporary: true, }) .await .unwrap(); Some(temp_pass) } }; 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 => { logger.log(Action::AdminCreateUser(&user)); format!("User {} was successfully created!", user.full_name()) } false => { logger.log(Action::AdminUpdateUser(&user)); format!("User {} was successfully updated!", user.full_name()) } }); if let Some(pass) = new_password { danger = Some(format!( "{}'s temporary password is {}", user.full_name(), pass )); } } } let users = users.send(users_actor::GetAllUsersRequest).await.unwrap().0; HttpResponse::Ok().body( UsersListTemplate { _p: 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 { _p: BaseSettingsPage::get("Create a new user", user.deref(), None, None), u: Default::default(), clients: clients.cloned(), } .render() .unwrap(), ) } #[derive(serde::Deserialize)] pub struct EditUserQuery { id: UserID, } pub async fn edit_user( user: CurrentUser, clients: web::Data, users: web::Data>, query: web::Query, ) -> impl Responder { let edited_account = users .send(users_actor::GetUserRequest(query.0.id)) .await .unwrap() .0; HttpResponse::Ok().body( EditUserTemplate { _p: BaseSettingsPage::get( "Edit user account", user.deref(), match edited_account.is_none() { true => Some("Could not find requested user!".to_string()), false => None, }, None, ), u: edited_account.unwrap_or_default(), clients: clients.cloned(), } .render() .unwrap(), ) }