feat: Enhance validation and permissions handling across controllers

- Added `ValidatedJson` extractor for automatic JSON validation in `events_controller.rs`, `testimonials_controller.rs`, `mentors_controller.rs`, `gacha_items_controller.rs`, and `hackathon_controller.rs`.
- Replaced manual permission checks with `require_permissions!` and `require_auth!` macros in relevant controllers to streamline permission handling.
- Introduced `sanitization` utilities in `sanitization.rs` for improved input sanitization.
- Added `permission_macros.rs` to encapsulate permission checking logic and reduce boilerplate.
- Updated dependencies in `Cargo.toml` to include `serde_json` and `validator`.
- Implemented error handling improvements in `notification_service.rs` for better response management.
This commit is contained in:
MythEclipse
2025-10-28 14:04:41 +07:00
parent d4a6c4c9ea
commit b9a51ce6cc
17 changed files with 551 additions and 225 deletions
+4
View File
@@ -1,4 +1,5 @@
pub mod v1;
pub mod permission_macros;
// Re-export core entity types used throughout the IAM module
pub use imphnen_entities::{
@@ -71,6 +72,9 @@ pub use v1::{
permissions_guard,
};
// Export permission macros
pub use permission_macros::{check_permissions, check_authenticated};
// Export IAM-specific types
pub use v1::auth::{
AuthRepository, AuthOtpSchema,
+115
View File
@@ -0,0 +1,115 @@
//! Permission guard utilities and macros to reduce boilerplate
//!
//! This module provides utilities to simplify permission checking in handlers
use axum::{
extract::Extension,
http::HeaderMap,
response::Response,
};
use imphnen_entities::PermissionsEnum;
use crate::AppState;
use crate::permissions_guard;
use imphnen_libs::jsonwebtoken::Claims;
/// Result type for permission-guarded handlers
pub type PermissionGuardResult<T> = Result<(T, AppState), Response>;
/// Helper function to extract user and check permissions
///
/// This is a cleaner wrapper around the existing permissions_guard
pub async fn check_permissions(
headers: HeaderMap,
state: Extension<AppState>,
required_permissions: Vec<PermissionsEnum>,
) -> PermissionGuardResult<Claims> {
match permissions_guard(headers, state, required_permissions).await {
Ok((user, state)) => Ok((user, state)),
Err(response) => Err(response),
}
}
/// Helper function for endpoints that don't require specific permissions
/// but still need authentication
pub async fn check_authenticated(
headers: HeaderMap,
state: Extension<AppState>,
) -> PermissionGuardResult<Claims> {
check_permissions(headers, state, vec![]).await
}
/// Macro to reduce boilerplate in permission-guarded handlers
///
/// # Example
/// ```rust
/// use imphnen_iam::require_permissions;
/// use imphnen_entities::PermissionsEnum;
///
/// pub async fn get_user_list(
/// headers: HeaderMap,
/// Extension(state): Extension<AppState>,
/// Query(meta): Query<MetaRequestDto>,
/// ) -> Response {
/// require_permissions!(headers, state, [PermissionsEnum::ReadListUsers], {
/// UsersService::get_user_list(&state, meta).await
/// })
/// }
/// ```
#[macro_export]
macro_rules! require_permissions {
($headers:expr, $state:expr, [$($perm:expr),*], $body:block) => {
{
let state_clone = $state.clone();
match $crate::permissions_guard(
$headers,
axum::extract::Extension(state_clone),
vec![$($perm),*],
)
.await
{
Ok((_user, _state_inner)) => {
let state = &$state;
$body
}
Err(response) => response,
}
}
};
}
/// Macro for authenticated-only handlers (no specific permissions)
#[macro_export]
macro_rules! require_auth {
($headers:expr, $state:expr, $body:block) => {
{
let state_clone = $state.clone();
match $crate::permissions_guard($headers, axum::extract::Extension(state_clone), vec![]).await {
Ok((_user, _state_inner)) => {
let state = &$state;
$body
}
Err(response) => response,
}
}
};
}
/// Macro for handlers that need access to the authenticated user
#[macro_export]
macro_rules! with_user {
($headers:expr, $state:expr, [$($perm:expr),*], |$user:ident, $state_var:ident| $body:block) => {
{
let state_clone = $state.clone();
match $crate::permissions_guard(
$headers,
axum::extract::Extension(state_clone),
vec![$($perm),*],
)
.await
{
Ok(($user, $state_var)) => $body,
Err(response) => response,
}
}
};
}