home_handler.rs
186 lignes · 6178 octets
/// Home Handler /// Feature 004: UI Post-Auth /// /// Handles the home page after user authentication. use askama::Template; use axum::{ extract::{Extension, State}, response::IntoResponse, }; use sea_orm::DatabaseConnection; use std::collections::HashMap; use std::sync::Arc; use crate::dto::home_dto::AccountStatDTO; use crate::dto::navigation_dto::NavigationDTO; use crate::dto::user_profile_dto::UserProfileDTO; use rustwarden_core::auth::jwt::Claims; use rustwarden_core::error::AppError; use rustwarden_core::i18n::extractor::Locale; use rustwarden_core::i18n::service::I18nService; use rustwarden_core::services::user_service::UserService; /// Home page template #[derive(Template)] #[template(path = "home.html")] #[allow(dead_code)] struct HomeTemplate { page_title: String, csrf_token: String, app_name: String, app_version: String, app_domain: String, app_description: String, analytics_opt_out: crate::analytics::AnalyticsOptOutContext, username: String, email: String, initials: String, avatar_color: String, roles_text: String, nav_items: Vec<NavItem>, has_pending_password_change: bool, welcome_message: String, home_subtitle: String, home_my_account: String, account_stats: Vec<AccountStatDTO>, user_menu_profile: String, user_menu_logout: String, } /// Simplified navigation item for templates #[derive(Clone)] #[allow(dead_code)] struct NavItem { #[allow(dead_code)] id: String, label: String, icon: String, url: String, active: bool, enabled: bool, badge: String, has_badge: bool, disabled_message: String, has_disabled_message: bool, } rustwarden_core::impl_template_response!(HomeTemplate); /// Handler for GET /home - Home page (PROTECTED) pub async fn home( Extension(claims): Extension<Claims>, Extension(i18n_service): Extension<Arc<I18nService>>, Extension(locale): Extension<Locale>, analytics: rustwarden_core::config::analytics::AnalyticsContext, State(db): State<DatabaseConnection>, ) -> Result<impl IntoResponse, AppError> { let username = claims.username.clone(); tracing::debug!("Rendering home page for user: {}", username); let user_model = UserService::get_user_by_username(&db, &username) .await? .ok_or_else(|| { tracing::warn!("User {} from session not found in database", username); AppError::NotFound("User not found".to_string()) })?; let roles = UserService::get_user_roles(&db, user_model.id).await?; let user = UserProfileDTO::new(user_model, roles.clone()); let locale_str = locale.as_str(); let mut vars = HashMap::new(); vars.insert("username".to_string(), user.username.clone()); let welcome_message = i18n_service .translate_with_vars("home.welcome", locale_str, &vars) .await; let home_subtitle = i18n_service.translate("home.subtitle", locale_str).await; let home_my_account = i18n_service.translate("home.my_account", locale_str).await; let stat_username_label = i18n_service .translate("home.stat_username", locale_str) .await; let stat_email_label = i18n_service.translate("home.stat_email", locale_str).await; let stat_member_since_label = i18n_service .translate("home.stat_member_since", locale_str) .await; let stat_roles_label = i18n_service.translate("home.stat_roles", locale_str).await; let account_stats = vec![ AccountStatDTO::new(&stat_username_label, &user.username, "user"), AccountStatDTO::new(&stat_email_label, &user.email, "mail"), AccountStatDTO::new( &stat_member_since_label, &user.created_at.format("%d/%m/%Y").to_string(), "calendar", ), AccountStatDTO::new(&stat_roles_label, &user.roles.join(", "), "shield"), ]; let user_menu_profile = i18n_service .translate("user_menu.profile", locale_str) .await; let user_menu_logout = i18n_service.translate("user_menu.logout", locale_str).await; let navigation = NavigationDTO::for_user(&roles, &i18n_service, &locale, Some(&db)).await; let nav_items: Vec<NavItem> = navigation .items .iter() .enumerate() .map(|(i, item)| NavItem { id: item.id.clone(), label: item.label.clone(), icon: item.icon.clone(), url: item.url.clone(), active: i == 0, enabled: item.enabled, badge: item.badge.clone(), has_badge: item.has_badge, disabled_message: item.disabled_message.clone(), has_disabled_message: item.has_disabled_message, }) .collect(); use rustwarden_core::services::app_settings_service::AppSettingsService; let app_domain = AppSettingsService::get_setting(&db, "app_domain") .await? .map(|s| s.value) .unwrap_or_else(|| "localhost".to_string()); let app_description = AppSettingsService::get_setting(&db, "app_description") .await? .map(|s| s.value) .unwrap_or_else(|| "User accounts and authentication".to_string()); let layout = rustwarden_core::templates::LayoutContext::new("", ""); let template = HomeTemplate { page_title: layout.page_title.clone(), csrf_token: layout.csrf_token.clone(), app_name: layout.app_name.clone(), app_version: layout.app_version.clone(), app_domain, app_description, analytics_opt_out: crate::analytics::AnalyticsOptOutContext::build( &analytics, &i18n_service, locale.as_str(), ) .await, username: user.username.clone(), email: user.email.clone(), initials: user.initials.clone(), avatar_color: user.avatar_color.clone(), roles_text: user.roles.join(", "), nav_items, has_pending_password_change: false, welcome_message, home_subtitle, home_my_account, account_stats, user_menu_profile, user_menu_logout, }; Ok(template) }
GitRust