domain: add PermissionChecker service with additive role evaluation

This commit is contained in:
2026-05-31 03:20:28 +02:00
parent cebb4cdaf1
commit 04811ff436
3 changed files with 64 additions and 1 deletions

View File

@@ -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()
}
}

View File

@@ -0,0 +1 @@
mod permission_service;

View 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,
));
}