1use crate::types::{DecideError, Resource, RoleMap, User};
2use crate::utils::{evaluate_condition};
3use std::fs::{self};
4
5pub struct Decide {
7 roles: RoleMap,
8}
9
10impl Decide {
11 pub fn new (roles: RoleMap) -> Self {
13 Self {
14 roles,
15 }
16 }
17
18 pub fn from_file (path: &str) -> Result<Self, Box<dyn std::error::Error>> {
20 let content = fs::read_to_string(path)?;
21 let roles: RoleMap = serde_json::from_str(&content)?;
22 Ok(Self::new(roles))
23 }
24
25 pub fn default () -> Result<Self, Box<dyn std::error::Error>> {
27 Self::from_file("decide.config.json")
28 }
29
30 pub fn can (&self, user: &User, action: &str, resource: &Resource) -> Result<bool, DecideError> {
31 for role_name in &user.roles {
32 if let Some(role) = self.roles.get(role_name) {
33 for pmsn in &role.permissions {
34 if pmsn.action != action {
35 continue;
36 }
37
38 match &pmsn.condition {
39 Some(expr) => {
40 let passed = evaluate_condition(expr, user, resource);
41 if passed {
42 return Ok(true);
43 }
44 }
45 None => {
46 return Ok(true);
47 }
48 }
49 }
50 } else {
51 return Err(DecideError::MissingRole(role_name.clone()));
52 }
53 }
54
55 Ok(false)
56 }
57}
58