use crate::utils::{auth::*, config::ConfigManager, error::*, DbPool}; use axum::{extract::State, response::Json}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct ConfigRequest { pub key: String, pub value: String, } #[derive(Debug, Serialize, Deserialize)] pub struct ConfigResponse { pub key: String, pub value: String, } #[derive(Debug, Serialize, Deserialize)] pub struct ConfigDefinition { pub key: String, pub description: String, pub value: Option, pub default_value: Option, pub required: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct ConfigListResponse { pub configs: Vec, } pub async fn get_all_configs( auth_user: AuthUser, State(pool): State, ) -> Result, AppError> { if auth_user.user.role != crate::utils::models::UserRole::Admin { return Err(forbidden_error("Admin access required")); } let allowed_configs = vec![ ConfigDefinition { key: "EXTERNAL_URL".to_string(), description: "The external URL used for provisioning codes. This should be the public URL where this server can be reached.".to_string(), value: ConfigManager::get_config(&pool, "EXTERNAL_URL").await?, default_value: Some("https://your-domain.com".to_string()), required: true, }, ConfigDefinition { key: "SESSION_TIMEOUT_HOURS".to_string(), description: "Number of hours before user sessions expire and require re-authentication.".to_string(), value: ConfigManager::get_config(&pool, "SESSION_TIMEOUT_HOURS").await?, default_value: Some("24".to_string()), required: false, }, ]; Ok(success_response(ConfigListResponse { configs: allowed_configs, })) } pub async fn set_config( auth_user: AuthUser, State(pool): State, Json(request): Json, ) -> Result, AppError> { if auth_user.user.role != crate::utils::models::UserRole::Admin { return Err(forbidden_error("Admin access required")); } let allowed_keys = vec!["EXTERNAL_URL", "SESSION_TIMEOUT_HOURS"]; if !allowed_keys.contains(&request.key.as_str()) { return Err(validation_error("Invalid configuration key")); } match request.key.as_str() { "EXTERNAL_URL" => { if request.value.trim().is_empty() { return Err(validation_error("External URL cannot be empty")); } if !request.value.starts_with("http://") && !request.value.starts_with("https://") { return Err(validation_error( "External URL must start with http:// or https://", )); } } "SESSION_TIMEOUT_HOURS" => { if request.value.parse::().is_err() || request.value.parse::().unwrap() <= 0 { return Err(validation_error("Value must be a positive number")); } } _ => {} } ConfigManager::set_config(&pool, &request.key, &request.value).await?; Ok(success_message("Configuration updated successfully")) } pub async fn get_config( auth_user: AuthUser, State(pool): State, axum::extract::Path(key): axum::extract::Path, ) -> Result, AppError> { if auth_user.user.role != crate::utils::models::UserRole::Admin { return Err(forbidden_error("Admin access required")); } let value = ConfigManager::get_config(&pool, &key) .await? .ok_or_else(|| not_found_error("Configuration key not found"))?; Ok(success_response(ConfigResponse { key, value })) }