1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5pub struct Acl {
6 pub id: Uuid,
7 pub memory_id: Uuid,
8 pub principal_type: PrincipalType,
9 pub principal_id: String,
10 pub permission: Permission,
11 pub granted_by: String,
12 pub created_at: String,
13 pub expires_at: Option<String>,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "snake_case")]
18pub enum Permission {
19 Read,
20 Write,
21 Delete,
22 Share,
23 Delegate,
24 Admin,
25}
26
27impl std::fmt::Display for Permission {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Permission::Read => write!(f, "read"),
31 Permission::Write => write!(f, "write"),
32 Permission::Delete => write!(f, "delete"),
33 Permission::Share => write!(f, "share"),
34 Permission::Delegate => write!(f, "delegate"),
35 Permission::Admin => write!(f, "admin"),
36 }
37 }
38}
39
40impl std::str::FromStr for Permission {
41 type Err = crate::error::Error;
42 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
43 match s {
44 "read" => Ok(Permission::Read),
45 "write" => Ok(Permission::Write),
46 "delete" => Ok(Permission::Delete),
47 "share" => Ok(Permission::Share),
48 "delegate" => Ok(Permission::Delegate),
49 "admin" => Ok(Permission::Admin),
50 _ => Err(crate::error::Error::Validation(format!(
51 "invalid permission: {s}"
52 ))),
53 }
54 }
55}
56
57impl Permission {
58 pub fn satisfies(&self, required: Permission) -> bool {
59 let level = |p: &Permission| -> u8 {
61 match p {
62 Permission::Read => 0,
63 Permission::Write => 1,
64 Permission::Delete => 2,
65 Permission::Share => 3,
66 Permission::Delegate => 4,
67 Permission::Admin => 5,
68 }
69 };
70 level(self) >= level(&required)
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
75#[serde(rename_all = "snake_case")]
76pub enum PrincipalType {
77 Agent,
78 Org,
79 Public,
80 User,
81 Role,
82}
83
84impl std::fmt::Display for PrincipalType {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 PrincipalType::Agent => write!(f, "agent"),
88 PrincipalType::Org => write!(f, "org"),
89 PrincipalType::Public => write!(f, "public"),
90 PrincipalType::User => write!(f, "user"),
91 PrincipalType::Role => write!(f, "role"),
92 }
93 }
94}
95
96impl std::str::FromStr for PrincipalType {
97 type Err = crate::error::Error;
98 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
99 match s {
100 "agent" => Ok(PrincipalType::Agent),
101 "org" => Ok(PrincipalType::Org),
102 "public" => Ok(PrincipalType::Public),
103 "user" => Ok(PrincipalType::User),
104 "role" => Ok(PrincipalType::Role),
105 _ => Err(crate::error::Error::Validation(format!(
106 "invalid principal type: {s}"
107 ))),
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_acl_serde_roundtrip() {
118 let acl = Acl {
119 id: Uuid::now_v7(),
120 memory_id: Uuid::now_v7(),
121 principal_type: PrincipalType::Agent,
122 principal_id: "agent-2".to_string(),
123 permission: Permission::Read,
124 granted_by: "agent-1".to_string(),
125 created_at: "2025-01-01T00:00:00Z".to_string(),
126 expires_at: None,
127 };
128 let json = serde_json::to_string(&acl).unwrap();
129 let deserialized: Acl = serde_json::from_str(&json).unwrap();
130 assert_eq!(acl, deserialized);
131 }
132
133 #[test]
134 fn test_permission_satisfies() {
135 assert!(Permission::Admin.satisfies(Permission::Read));
137 assert!(Permission::Admin.satisfies(Permission::Write));
138 assert!(Permission::Admin.satisfies(Permission::Delete));
139 assert!(Permission::Admin.satisfies(Permission::Share));
140 assert!(Permission::Admin.satisfies(Permission::Delegate));
141 assert!(Permission::Admin.satisfies(Permission::Admin));
142 assert!(Permission::Write.satisfies(Permission::Read));
144 assert!(Permission::Write.satisfies(Permission::Write));
145 assert!(!Permission::Write.satisfies(Permission::Admin));
146 assert!(!Permission::Write.satisfies(Permission::Delete));
147 assert!(Permission::Read.satisfies(Permission::Read));
149 assert!(!Permission::Read.satisfies(Permission::Write));
150 assert!(Permission::Delegate.satisfies(Permission::Share));
152 assert!(Permission::Delegate.satisfies(Permission::Delete));
153 assert!(!Permission::Delegate.satisfies(Permission::Admin));
154 }
155}