roles are now better

This commit is contained in:
filipriec
2025-08-30 13:19:45 +02:00
parent 60eb1c9f51
commit d6fd672409
5 changed files with 57 additions and 24 deletions

View File

@@ -26,6 +26,7 @@ use canvas::DataProvider;
use crate::state::app::state::AppState; use crate::state::app::state::AppState;
use crate::pages::admin::AdminState; use crate::pages::admin::AdminState;
use crate::state::pages::auth::AuthState; use crate::state::pages::auth::AuthState;
use crate::state::pages::auth::UserRole;
use crate::pages::login::LoginState; use crate::pages::login::LoginState;
use crate::pages::register::RegisterState; use crate::pages::register::RegisterState;
use crate::pages::intro::IntroState; use crate::pages::intro::IntroState;
@@ -528,7 +529,7 @@ impl EventHandler {
} }
} }
Page::Admin(state) => { Page::Admin(state) => {
if auth_state.role.as_deref() == Some("admin") { if matches!(auth_state.role, Some(UserRole::Admin)) {
if state.handle_movement(app_state, ma) { if state.handle_movement(app_state, ma) {
return Ok(EventOutcome::Ok(String::new())); return Ok(EventOutcome::Ok(String::new()));
} }
@@ -545,7 +546,7 @@ impl EventHandler {
// Optional page-specific handlers (non-movement or rich actions) // Optional page-specific handlers (non-movement or rich actions)
if let Page::Admin(admin_state) = &mut router.current { if let Page::Admin(admin_state) = &mut router.current {
if auth_state.role.as_deref() == Some("admin") { if matches!(auth_state.role, Some(UserRole::Admin)) {
// Full admin navigation // Full admin navigation
if handle_admin_navigation( if handle_admin_navigation(
key_event, key_event,
@@ -961,7 +962,7 @@ impl EventHandler {
"exit_highlight_mode" | "exit_highlight_mode" |
"save" | "save" |
"quit" | "quit" |
"force_quit" | "Force_quit" |
"save_and_quit" | "save_and_quit" |
"revert" | "revert" |
"enter_decider" | "enter_decider" |

View File

@@ -12,6 +12,7 @@ use ratatui::{
widgets::{Block, BorderType, Borders, List, ListItem, Paragraph, Wrap}, widgets::{Block, BorderType, Borders, List, ListItem, Paragraph, Wrap},
Frame, Frame,
}; };
use crate::state::pages::auth::UserRole;
use crate::pages::admin::admin::ui::render_admin_panel_admin; use crate::pages::admin::admin::ui::render_admin_panel_admin;
pub fn render_admin_panel( pub fn render_admin_panel(
@@ -44,23 +45,20 @@ pub fn render_admin_panel(
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) .constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
.split(chunks[1]); .split(chunks[1]);
if auth_state.role.as_deref() != Some("admin") { match auth_state.role {
render_admin_panel_non_admin( Some(UserRole::Admin) => {
f, render_admin_panel_admin(f, chunks[1], app_state, admin_state, theme);
admin_state, }
&content_chunks, _ => {
theme, render_admin_panel_non_admin(
profile_tree, f,
selected_profile, admin_state,
); &content_chunks,
} else { theme,
render_admin_panel_admin( profile_tree,
f, selected_profile,
chunks[1], );
app_state, }
admin_state,
theme,
);
} }
} }

View File

@@ -8,6 +8,7 @@ use crate::config::storage::storage::{StoredAuthData, save_auth_data};
use crate::ui::handlers::context::DialogPurpose; use crate::ui::handlers::context::DialogPurpose;
use common::proto::komp_ac::auth::LoginResponse; use common::proto::komp_ac::auth::LoginResponse;
use crate::pages::login::LoginFormState; use crate::pages::login::LoginFormState;
use crate::state::pages::auth::UserRole;
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};
use tokio::spawn; use tokio::spawn;
use tokio::sync::mpsc; use tokio::sync::mpsc;
@@ -56,7 +57,7 @@ pub async fn save(
// Store authentication details // Store authentication details
auth_state.auth_token = Some(response.access_token.clone()); auth_state.auth_token = Some(response.access_token.clone());
auth_state.user_id = Some(response.user_id.clone()); auth_state.user_id = Some(response.user_id.clone());
auth_state.role = Some(response.role.clone()); auth_state.role = Some(UserRole::from_str(&response.role));
auth_state.decoded_username = Some(response.username.clone()); auth_state.decoded_username = Some(response.username.clone());
login_state.set_has_unsaved_changes(false); login_state.set_has_unsaved_changes(false);
@@ -180,7 +181,7 @@ pub fn handle_login_result(
LoginResult::Success(response) => { LoginResult::Success(response) => {
auth_state.auth_token = Some(response.access_token.clone()); auth_state.auth_token = Some(response.access_token.clone());
auth_state.user_id = Some(response.user_id.clone()); auth_state.user_id = Some(response.user_id.clone());
auth_state.role = Some(response.role.clone()); auth_state.role = Some(UserRole::from_str(&response.role));
auth_state.decoded_username = Some(response.username.clone()); auth_state.decoded_username = Some(response.username.clone());
let data_to_store = StoredAuthData { let data_to_store = StoredAuthData {

View File

@@ -2,12 +2,44 @@
use canvas::{DataProvider, AppMode}; use canvas::{DataProvider, AppMode};
/// Strongly typed user roles
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UserRole {
Admin,
Moderator,
Accountant,
Viewer,
Unknown(String), // fallback for unexpected roles
}
impl UserRole {
pub fn from_str(s: &str) -> Self {
match s.trim().to_lowercase().as_str() {
"admin" => UserRole::Admin,
"moderator" => UserRole::Moderator,
"accountant" => UserRole::Accountant,
"viewer" => UserRole::Viewer,
other => UserRole::Unknown(other.to_string()),
}
}
pub fn as_str(&self) -> &str {
match self {
UserRole::Admin => "admin",
UserRole::Moderator => "moderator",
UserRole::Accountant => "accountant",
UserRole::Viewer => "viewer",
UserRole::Unknown(s) => s.as_str(),
}
}
}
/// Represents the authenticated session state /// Represents the authenticated session state
#[derive(Default)] #[derive(Default)]
pub struct AuthState { pub struct AuthState {
pub auth_token: Option<String>, pub auth_token: Option<String>,
pub user_id: Option<String>, pub user_id: Option<String>,
pub role: Option<String>, pub role: Option<UserRole>,
pub decoded_username: Option<String>, pub decoded_username: Option<String>,
} }

View File

@@ -9,6 +9,7 @@ use crate::modes::common::commands::CommandHandler;
use crate::modes::handlers::event::{EventHandler, EventOutcome}; use crate::modes::handlers::event::{EventHandler, EventOutcome};
use crate::modes::handlers::mode_manager::{AppMode, ModeManager}; use crate::modes::handlers::mode_manager::{AppMode, ModeManager};
use crate::state::pages::auth::AuthState; use crate::state::pages::auth::AuthState;
use crate::state::pages::auth::UserRole;
use crate::pages::login::LoginFormState; use crate::pages::login::LoginFormState;
use crate::pages::register::RegisterFormState; use crate::pages::register::RegisterFormState;
use crate::pages::admin::AdminState; use crate::pages::admin::AdminState;
@@ -84,7 +85,7 @@ pub async fn run_ui() -> Result<()> {
Ok(Some(stored_data)) => { Ok(Some(stored_data)) => {
auth_state.auth_token = Some(stored_data.access_token); auth_state.auth_token = Some(stored_data.access_token);
auth_state.user_id = Some(stored_data.user_id); auth_state.user_id = Some(stored_data.user_id);
auth_state.role = Some(stored_data.role); auth_state.role = Some(UserRole::from_str(&stored_data.role));
auth_state.decoded_username = Some(stored_data.username); auth_state.decoded_username = Some(stored_data.username);
auto_logged_in = true; auto_logged_in = true;
info!("Auth data loaded from file. User is auto-logged in."); info!("Auth data loaded from file. User is auto-logged in.");