domain: add PermissionChecker service with additive role evaluation
This commit is contained in:
@@ -1 +1,21 @@
|
||||
// Permission service — will be implemented in Task 5
|
||||
use std::collections::HashSet;
|
||||
use crate::entities::{Permission, PermissionAction, ResourceType, Role};
|
||||
|
||||
pub struct PermissionChecker;
|
||||
|
||||
impl PermissionChecker {
|
||||
pub fn has_permission(
|
||||
roles: &[Role],
|
||||
action: PermissionAction,
|
||||
resource_type: ResourceType,
|
||||
) -> bool {
|
||||
roles.iter().any(|role| {
|
||||
role.has_permission(action, resource_type)
|
||||
|| role.has_permission(action, ResourceType::Global)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn effective_permissions(roles: &[Role]) -> HashSet<Permission> {
|
||||
roles.iter().flat_map(|r| r.permissions.iter().copied()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
1
crates/domain/tests/services/mod.rs
Normal file
1
crates/domain/tests/services/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod permission_service;
|
||||
42
crates/domain/tests/services/permission_service.rs
Normal file
42
crates/domain/tests/services/permission_service.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use domain::entities::{Permission, PermissionAction, ResourceType, Role};
|
||||
use domain::entities::permission::{admin_permissions, viewer_permissions};
|
||||
use domain::services::permission_service::PermissionChecker;
|
||||
|
||||
#[test]
|
||||
fn viewer_can_read() {
|
||||
let role = Role::new("viewer", viewer_permissions(), true);
|
||||
assert!(PermissionChecker::has_permission(
|
||||
&[role],
|
||||
PermissionAction::ReadAsset,
|
||||
ResourceType::Asset,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn viewer_cannot_delete() {
|
||||
let role = Role::new("viewer", viewer_permissions(), true);
|
||||
assert!(!PermissionChecker::has_permission(
|
||||
&[role],
|
||||
PermissionAction::DeleteAsset,
|
||||
ResourceType::Asset,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roles_additive() {
|
||||
let r1 = Role::new("r1", [Permission::new(PermissionAction::ReadAsset, ResourceType::Global)].into(), false);
|
||||
let r2 = Role::new("r2", [Permission::new(PermissionAction::WriteMetadata, ResourceType::Global)].into(), false);
|
||||
let eff = PermissionChecker::effective_permissions(&[r1, r2]);
|
||||
assert_eq!(eff.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_covers_specific() {
|
||||
let role = Role::new("admin", admin_permissions(), true);
|
||||
// Global ReadAsset should cover Asset-scoped check
|
||||
assert!(PermissionChecker::has_permission(
|
||||
&[role],
|
||||
PermissionAction::ReadAsset,
|
||||
ResourceType::Album,
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user