pub mod resource;
pub mod filters;
pub mod pagination;
pub mod error;
pub mod router;
pub mod menu;
pub mod registry;
pub mod health;
pub mod middleware;
pub mod nested;
pub mod utils;
pub mod actions;
pub mod helpers;
pub mod controllers;
pub mod configs;
pub mod models;
pub mod schemas;
pub mod errors;
pub use schemas::adminx_schema::AdminxSchema;
pub use configs::initializer::{
get_adminx_config,
setup_adminx_logging,
get_adminx_session_middleware,
adminx_initialize,
AdminxConfig
};
pub use utils::{
jwt::create_jwt_token, auth::{extract_claims_from_session, AdminxStatus, NewAdminxUser, InitOutcome},
structs::{LoginForm, RoleGuard, Claims}, };
pub use resource::AdmixResource;
pub use models::adminx_model::{AdminxUser, AdminxUserPublic};
pub use controllers::{
auth_controller::{login_form, login_action, logout_action},
dashboard_controller::{adminx_home, adminx_stats, adminx_profile},
};
pub use router::register_all_admix_routes;
pub use helpers::template_helper::{
render_template,
render_template_with_auth,
render_protected_template,
render_404,
render_403,
render_500,
};
pub use middleware::role_guard::RoleGuardMiddleware;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const NAME: &str = env!("CARGO_PKG_NAME");
pub mod prelude {
pub use crate::{
AdminxConfig,
adminx_initialize,
Claims, AdminxUser,
LoginForm,
RoleGuard,
render_template,
extract_claims_from_session,
AdmixResource, };
}
pub fn validate_config() -> Result<(), Box<dyn std::error::Error>> {
use std::env;
let required_vars = vec![
"JWT_SECRET",
];
for var in required_vars {
if env::var(var).is_err() {
return Err(format!("Required environment variable {} is not set", var).into());
}
}
Ok(())
}
pub async fn health_check() -> Result<serde_json::Value, Box<dyn std::error::Error>> {
use crate::utils::database::check_database_health;
let db_healthy = check_database_health().await.unwrap_or(false);
Ok(serde_json::json!({
"status": if db_healthy { "healthy" } else { "unhealthy" },
"version": VERSION,
"name": NAME,
"database": if db_healthy { "connected" } else { "disconnected" },
"timestamp": chrono::Utc::now().to_rfc3339(),
}))
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
#[test]
fn test_version_info() {
assert!(!VERSION.is_empty());
assert_eq!(NAME, "adminx");
}
#[test]
fn test_config_validation() {
env::set_var("JWT_SECRET", "test_secret_that_is_long_enough_for_testing");
assert!(validate_config().is_ok());
env::remove_var("JWT_SECRET");
assert!(validate_config().is_err());
}
#[test]
fn test_claims_consistency() {
use crate::utils::structs::Claims;
let claims = Claims {
sub: "test_user".to_string(),
exp: 1234567890,
email: "test@example.com".to_string(),
role: "admin".to_string(),
roles: vec!["admin".to_string()],
};
assert_eq!(claims.role, "admin");
assert_eq!(claims.email, "test@example.com");
assert!(claims.roles.contains(&"admin".to_string()));
}
#[test]
fn test_prelude_imports() {
use crate::prelude::*;
let _config_exists = std::marker::PhantomData::<AdminxConfig>;
let _claims_exists = std::marker::PhantomData::<Claims>;
let _resource_exists = std::marker::PhantomData::<Box<dyn AdmixResource>>;
}
}