1use crate::{
8 core::RoleSystem, error::Result, permission::Permission, storage::Storage, subject::Subject,
9};
10use std::collections::{HashMap, HashSet};
11
12pub struct RoleQuery<'a, S: Storage> {
14 system: &'a RoleSystem<S>,
15}
16
17pub trait RoleSystemQuery<S: Storage> {
19 fn query(&self) -> RoleQuery<'_, S>;
21}
22
23impl<S: Storage> RoleSystemQuery<S> for RoleSystem<S> {
24 fn query(&self) -> RoleQuery<'_, S> {
25 RoleQuery { system: self }
26 }
27}
28
29impl<'a, S: Storage> RoleQuery<'a, S> {
30 pub fn find_subjects_with_role(&self, role_name: &str) -> Result<Vec<String>> {
32 let mut subjects = Vec::new();
33
34 for entry in self.system.subject_roles() {
35 let (subject_id, roles) = (entry.key(), entry.value());
36 if roles.contains(role_name) {
37 subjects.push(subject_id.clone());
38 }
39 }
40
41 Ok(subjects)
42 }
43
44 pub fn subjects_with_any_role(&self, role_names: &[&str]) -> Result<Vec<String>> {
46 let mut subjects = Vec::new();
47 let role_set: HashSet<&str> = role_names.iter().copied().collect();
48
49 for entry in self.system.subject_roles() {
50 let (subject_id, roles) = (entry.key(), entry.value());
51 if roles.iter().any(|role| role_set.contains(role.as_str())) {
52 subjects.push(subject_id.clone());
53 }
54 }
55
56 Ok(subjects)
57 }
58
59 pub fn subjects_with_all_roles(&self, role_names: &[&str]) -> Result<Vec<String>> {
61 let mut subjects = Vec::new();
62 let role_set: HashSet<&str> = role_names.iter().copied().collect();
63
64 for entry in self.system.subject_roles() {
65 let (subject_id, roles) = (entry.key(), entry.value());
66 let subject_role_set: HashSet<&str> = roles.iter().map(|s| s.as_str()).collect();
67 if role_set.is_subset(&subject_role_set) {
68 subjects.push(subject_id.clone());
69 }
70 }
71
72 Ok(subjects)
73 }
74
75 pub fn effective_permissions(&self, subject: &Subject) -> Result<Vec<Permission>> {
77 let mut permissions = Vec::new();
78 let subject_roles = self.system.get_subject_roles(subject)?;
79
80 for role_name in subject_roles {
81 if let Some(role) = self.system.get_role(&role_name)? {
82 for permission in role.permissions().permissions() {
83 if !permissions.contains(permission) {
84 permissions.push(permission.clone());
85 }
86 }
87 }
88 }
89
90 Ok(permissions)
91 }
92
93 pub fn roles_with_permission(&self, permission: &Permission) -> Result<Vec<String>> {
95 let mut matching_roles = Vec::new();
96 let role_names = self.system.storage().list_roles()?;
97
98 for role_name in role_names {
99 if let Some(role) = self.system.storage().get_role(&role_name)?
100 && role.permissions().permissions().contains(permission)
101 {
102 matching_roles.push(role_name);
103 }
104 }
105
106 Ok(matching_roles)
107 }
108
109 pub fn role_hierarchy(&self) -> HashMap<String, Vec<String>> {
111 let mut hierarchy = HashMap::new();
112
113 for entry in self.system.role_hierarchy() {
114 let (child, parents) = (entry.key(), entry.value());
115 hierarchy.insert(child.clone(), parents.iter().cloned().collect());
116 }
117
118 hierarchy
119 }
120
121 pub fn parent_roles(&self, child_role: &str) -> Vec<String> {
123 if let Some(parents) = self.system.role_hierarchy().get(child_role) {
124 parents.iter().cloned().collect()
125 } else {
126 Vec::new()
127 }
128 }
129
130 pub fn child_roles(&self, parent_role: &str) -> Vec<String> {
132 let mut children = Vec::new();
133
134 for entry in self.system.role_hierarchy() {
135 let (child, parents) = (entry.key(), entry.value());
136 if parents.contains(parent_role) {
137 children.push(child.clone());
138 }
139 }
140
141 children
142 }
143
144 pub fn system_statistics(&self) -> Result<SystemStatistics> {
146 let roles = self.system.storage().list_roles()?;
147 let mut total_permissions = 0;
148
149 for role_name in &roles {
150 if let Some(role) = self.system.storage().get_role(role_name)? {
151 total_permissions += role.permissions().permissions().len();
152 }
153 }
154
155 let mut unique_subjects = HashSet::new();
157 for entry in self.system.subject_roles() {
158 unique_subjects.insert(entry.key().clone());
159 }
160
161 Ok(SystemStatistics {
162 total_roles: roles.len(),
163 total_permissions,
164 total_subjects: unique_subjects.len(),
165 total_role_assignments: self.count_role_assignments()?,
166 })
167 }
168
169 pub fn permission_coverage(&self, subjects: &[Subject]) -> Result<PermissionCoverage> {
171 let mut permission_counts: HashMap<String, usize> = HashMap::new();
172
173 for subject in subjects {
174 let permissions = self.effective_permissions(subject)?;
175 for permission in permissions {
176 let perm_str = format!("{}:{}", permission.action(), permission.resource_type());
177 *permission_counts.entry(perm_str).or_insert(0) += 1;
178 }
179 }
180
181 let all_roles = self.system.storage().list_roles()?;
182 let mut total_possible_permissions = 0;
183
184 for role_name in &all_roles {
185 if let Some(role) = self.system.storage().get_role(role_name)? {
186 total_possible_permissions += role.permissions().permissions().len();
187 }
188 }
189
190 Ok(PermissionCoverage {
191 permission_usage: permission_counts,
192 total_possible_permissions,
193 subjects_analyzed: subjects.len(),
194 })
195 }
196
197 pub fn unused_roles(&self) -> Result<Vec<String>> {
199 let all_roles = self.system.storage().list_roles()?;
200 let mut used_roles = HashSet::new();
201
202 for entry in self.system.subject_roles() {
203 for role in entry.value().iter() {
204 used_roles.insert(role.clone());
205 }
206 }
207
208 Ok(all_roles
209 .into_iter()
210 .filter(|role| !used_roles.contains(role))
211 .collect())
212 }
213
214 pub fn max_hierarchy_depth(&self) -> Result<usize> {
216 let roles = self.system.storage().list_roles()?;
217 let mut max_depth = 0;
218
219 for role_name in roles {
220 let depth = self.calculate_role_depth(&role_name, &mut HashSet::new(), 0)?;
221 max_depth = max_depth.max(depth);
222 }
223
224 Ok(max_depth)
225 }
226
227 fn calculate_role_depth(
229 &self,
230 role: &str,
231 visited: &mut HashSet<String>,
232 current_depth: usize,
233 ) -> Result<usize> {
234 if current_depth >= self.system.config().max_hierarchy_depth {
235 return Ok(current_depth);
236 }
237
238 if !visited.insert(role.to_string()) {
239 return Ok(current_depth); }
241
242 let mut max_child_depth = current_depth;
243
244 if let Some(parents) = self.system.role_hierarchy().get(role) {
245 for parent in parents.iter() {
246 let parent_depth = self.calculate_role_depth(parent, visited, current_depth + 1)?;
247 max_child_depth = max_child_depth.max(parent_depth);
248 }
249 }
250
251 visited.remove(role);
252 Ok(max_child_depth)
253 }
254
255 fn count_role_assignments(&self) -> Result<usize> {
257 let mut total = 0;
258 for entry in self.system.subject_roles() {
259 total += entry.value().len();
260 }
261 Ok(total)
262 }
263}
264
265#[derive(Debug, Clone)]
267pub struct SystemStatistics {
268 pub total_roles: usize,
270 pub total_permissions: usize,
272 pub total_subjects: usize,
274 pub total_role_assignments: usize,
276}
277
278#[derive(Debug, Clone)]
280pub struct PermissionCoverage {
281 pub permission_usage: HashMap<String, usize>,
283 pub total_possible_permissions: usize,
285 pub subjects_analyzed: usize,
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use crate::{
293 core::RoleSystem, permission::Permission, role::Role, storage::MemoryStorage,
294 subject::Subject,
295 };
296
297 #[test]
298 fn test_query_interface() {
299 let mut system = RoleSystem::<MemoryStorage>::new();
300
301 let admin_role = Role::new("admin")
303 .add_permission(Permission::new("read", "documents"))
304 .add_permission(Permission::new("write", "documents"));
305
306 let user_role = Role::new("user").add_permission(Permission::new("read", "documents"));
307
308 system.register_role(admin_role).unwrap();
309 system.register_role(user_role).unwrap();
310
311 let admin_user = Subject::user("admin1");
312 let regular_user = Subject::user("user1");
313
314 system.assign_role(&admin_user, "admin").unwrap();
315 system.assign_role(®ular_user, "user").unwrap();
316
317 let query = system.query();
319
320 let admin_subjects = query.find_subjects_with_role("admin").unwrap();
321 assert_eq!(admin_subjects.len(), 1);
322 assert!(admin_subjects.contains(&"admin1".to_string()));
323
324 let user_subjects = query.find_subjects_with_role("user").unwrap();
325 assert_eq!(user_subjects.len(), 1);
326 assert!(user_subjects.contains(&"user1".to_string()));
327
328 let read_permission = Permission::new("read", "documents");
329 let roles_with_read = query.roles_with_permission(&read_permission).unwrap();
330 assert_eq!(roles_with_read.len(), 2);
331 assert!(roles_with_read.contains(&"admin".to_string()));
332 assert!(roles_with_read.contains(&"user".to_string()));
333
334 let stats = query.system_statistics().unwrap();
335 assert_eq!(stats.total_roles, 2);
336 assert_eq!(stats.total_subjects, 2);
337 assert_eq!(stats.total_role_assignments, 2);
338 }
339
340 #[test]
341 fn test_permission_coverage() {
342 let mut system = RoleSystem::<MemoryStorage>::new();
343
344 let role = Role::new("test").add_permission(Permission::new("read", "docs"));
345
346 system.register_role(role).unwrap();
347
348 let user = Subject::user("test_user");
349 system.assign_role(&user, "test").unwrap();
350
351 let query = system.query();
352 let coverage = query.permission_coverage(&[user]).unwrap();
353
354 assert_eq!(coverage.subjects_analyzed, 1);
355 assert!(coverage.permission_usage.contains_key("read:docs"));
356 }
357
358 #[test]
359 fn test_hierarchy_queries() {
360 let mut system = RoleSystem::<MemoryStorage>::new();
361
362 let parent_role = Role::new("parent");
363 let child_role = Role::new("child");
364
365 system.register_role(parent_role).unwrap();
366 system.register_role(child_role).unwrap();
367 system.add_role_inheritance("child", "parent").unwrap();
368
369 let query = system.query();
370
371 let parents = query.parent_roles("child");
372 assert_eq!(parents.len(), 1);
373 assert!(parents.contains(&"parent".to_string()));
374
375 let children = query.child_roles("parent");
376 assert_eq!(children.len(), 1);
377 assert!(children.contains(&"child".to_string()));
378 }
379}