use axum::{extract::State, response::IntoResponse, Form}; use chrono_tz::TZ_VARIANTS; use serde::{Deserialize, Serialize}; use crate::{ middleware_auth::RequireUser, template_response::{HtmlError, TemplateResponse}, AuthSessionType, }; use common::storage::types::user::User; use crate::html_state::HtmlState; #[derive(Serialize)] pub struct AccountPageData { user: User, timezones: Vec, } pub async fn show_account_page( RequireUser(user): RequireUser, ) -> Result { let timezones = TZ_VARIANTS.iter().map(|tz| tz.to_string()).collect(); Ok(TemplateResponse::new_template( "auth/account_settings.html", AccountPageData { user, timezones }, )) } pub async fn set_api_key( State(state): State, RequireUser(user): RequireUser, auth: AuthSessionType, ) -> Result { // Generate and set the API key let api_key = User::set_api_key(&user.id, &state.db).await?; // Clear the cache so new requests have access to the user with api key auth.cache_clear_user(user.id.to_string()); // Update the user's API key let updated_user = User { api_key: Some(api_key), ..user.clone() }; // Render the API key section block Ok(TemplateResponse::new_partial( "auth/account_settings.html", "api_key_section", AccountPageData { user: updated_user, timezones: vec![], }, )) } pub async fn delete_account( State(state): State, RequireUser(user): RequireUser, auth: AuthSessionType, ) -> Result { state.db.delete_item::(&user.id).await?; auth.logout_user(); auth.session.destroy(); Ok(TemplateResponse::redirect("/")) } #[derive(Deserialize)] pub struct UpdateTimezoneForm { timezone: String, } pub async fn update_timezone( State(state): State, RequireUser(user): RequireUser, auth: AuthSessionType, Form(form): Form, ) -> Result { User::update_timezone(&user.id, &form.timezone, &state.db).await?; // Clear the cache auth.cache_clear_user(user.id.to_string()); // Update the user's API key let updated_user = User { timezone: form.timezone, ..user.clone() }; let timezones = TZ_VARIANTS.iter().map(|tz| tz.to_string()).collect(); // Render the API key section block Ok(TemplateResponse::new_partial( "auth/account_settings.html", "timezone_section", AccountPageData { user: updated_user, timezones, }, )) } pub async fn show_change_password( RequireUser(_user): RequireUser, ) -> Result { Ok(TemplateResponse::new_template( "auth/change_password_form.html", {}, )) } #[derive(Deserialize)] pub struct NewPasswordForm { old_password: String, new_password: String, } pub async fn change_password( State(state): State, RequireUser(user): RequireUser, auth: AuthSessionType, Form(form): Form, ) -> Result { // Authenticate to make sure the password matches let authenticated_user = User::authenticate(&user.email, &form.old_password, &state.db).await?; User::patch_password(&authenticated_user.email, &form.new_password, &state.db).await?; auth.cache_clear_user(user.id); Ok(TemplateResponse::new_partial( "auth/account_settings.html", "change_password_section", {}, )) }