1use std::collections::HashMap;
2
3use claw10_domain::{Permission, RoleId};
4
5pub struct RbacService {
6 role_permissions: HashMap<RoleId, Vec<Permission>>,
7}
8
9impl RbacService {
10 #[must_use]
11 pub fn new() -> Self {
12 Self {
13 role_permissions: HashMap::new(),
14 }
15 }
16
17 pub fn assign_permissions(&mut self, role_id: RoleId, permissions: Vec<Permission>) {
18 self.role_permissions.insert(role_id, permissions);
19 }
20
21 #[must_use]
22 pub fn get_role_permissions(&self, role_id: &RoleId) -> Vec<Permission> {
23 self.role_permissions
24 .get(role_id)
25 .cloned()
26 .unwrap_or_default()
27 }
28
29 #[must_use]
30 pub fn get_roles_permissions(&self, role_ids: &[RoleId]) -> Vec<Permission> {
31 let mut perms: Vec<Permission> = role_ids
32 .iter()
33 .flat_map(|rid| self.get_role_permissions(rid))
34 .collect();
35 perms.sort();
36 perms.dedup();
37 perms
38 }
39
40 #[must_use]
41 pub fn child_permissions(
42 parent_delegable: &[Permission],
43 requested: &[Permission],
44 ) -> Vec<Permission> {
45 let parent_set: std::collections::HashSet<&Permission> = parent_delegable.iter().collect();
46 requested
47 .iter()
48 .filter(|p| parent_set.contains(*p))
49 .cloned()
50 .collect()
51 }
52}
53
54impl Default for RbacService {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use uuid::Uuid;
64
65 fn create_role_id() -> RoleId {
66 RoleId(Uuid::now_v7())
67 }
68
69 fn create_permission(name: &str) -> Permission {
70 Permission(name.to_string())
71 }
72
73 #[test]
74 fn test_get_roles_permissions_empty() {
75 let rbac = RbacService::new();
76 let perms = rbac.get_roles_permissions(&[]);
77 assert!(perms.is_empty());
78 }
79
80 #[test]
81 fn test_get_roles_permissions_single_role() {
82 let mut rbac = RbacService::new();
83 let role1 = create_role_id();
84 let p1 = create_permission("read");
85 let p2 = create_permission("write");
86 rbac.assign_permissions(role1.clone(), vec![p1.clone(), p2.clone()]);
87
88 let perms = rbac.get_roles_permissions(&[role1]);
89 assert_eq!(perms.len(), 2);
90 assert!(perms.contains(&p1));
91 assert!(perms.contains(&p2));
92 }
93
94 #[test]
95 fn test_get_roles_permissions_multiple_roles() {
96 let mut rbac = RbacService::new();
97
98 let role1 = create_role_id();
99 let p1 = create_permission("read");
100 rbac.assign_permissions(role1.clone(), vec![p1.clone()]);
101
102 let role2 = create_role_id();
103 let p2 = create_permission("write");
104 rbac.assign_permissions(role2.clone(), vec![p2.clone()]);
105
106 let perms = rbac.get_roles_permissions(&[role1, role2]);
107 assert_eq!(perms.len(), 2);
108 assert!(perms.contains(&p1));
109 assert!(perms.contains(&p2));
110 }
111
112 #[test]
113 fn test_get_roles_permissions_duplicate_permissions() {
114 let mut rbac = RbacService::new();
115
116 let role1 = create_role_id();
117 let p1 = create_permission("read");
118 let p2 = create_permission("write");
119 rbac.assign_permissions(role1.clone(), vec![p1.clone(), p2.clone()]);
120
121 let role2 = create_role_id();
122 let p3 = create_permission("write"); let p4 = create_permission("delete");
124 rbac.assign_permissions(role2.clone(), vec![p3.clone(), p4.clone()]);
125
126 let perms = rbac.get_roles_permissions(&[role1, role2]);
127 assert_eq!(perms.len(), 3);
128 assert!(perms.contains(&p1));
129 assert!(perms.contains(&p2));
130 assert!(perms.contains(&p4));
131 }
132
133 #[test]
134 fn test_get_roles_permissions_missing_roles() {
135 let mut rbac = RbacService::new();
136
137 let role1 = create_role_id();
138 let p1 = create_permission("read");
139 rbac.assign_permissions(role1.clone(), vec![p1.clone()]);
140
141 let role_missing = create_role_id();
142
143 let perms = rbac.get_roles_permissions(&[role1, role_missing]);
144 assert_eq!(perms.len(), 1);
145 assert!(perms.contains(&p1));
146 }
147}