1use crate::error::{CollabError, Result};
4use crate::models::UserRole;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
9pub enum Permission {
10 WorkspaceCreate,
12 WorkspaceRead,
14 WorkspaceUpdate,
16 WorkspaceDelete,
18 WorkspaceArchive,
20 WorkspaceManageMembers,
22
23 MockCreate,
25 MockRead,
27 MockUpdate,
29 MockDelete,
31
32 InviteMembers,
34 RemoveMembers,
36 ChangeRoles,
38
39 ViewHistory,
41 CreateSnapshot,
43 RestoreSnapshot,
45
46 ManageSettings,
48 ManageIntegrations,
50
51 ScenarioModifyChaosRules,
54 ScenarioModifyRealityDefaults,
56 ScenarioPromote,
58 ScenarioApprove,
60 ScenarioModifyDriftBudgets,
62}
63
64impl std::fmt::Display for Permission {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match self {
67 Self::WorkspaceCreate => write!(f, "WorkspaceCreate"),
68 Self::WorkspaceRead => write!(f, "WorkspaceRead"),
69 Self::WorkspaceUpdate => write!(f, "WorkspaceUpdate"),
70 Self::WorkspaceDelete => write!(f, "WorkspaceDelete"),
71 Self::WorkspaceArchive => write!(f, "WorkspaceArchive"),
72 Self::WorkspaceManageMembers => write!(f, "WorkspaceManageMembers"),
73 Self::MockCreate => write!(f, "MockCreate"),
74 Self::MockRead => write!(f, "MockRead"),
75 Self::MockUpdate => write!(f, "MockUpdate"),
76 Self::MockDelete => write!(f, "MockDelete"),
77 Self::InviteMembers => write!(f, "InviteMembers"),
78 Self::RemoveMembers => write!(f, "RemoveMembers"),
79 Self::ChangeRoles => write!(f, "ChangeRoles"),
80 Self::ViewHistory => write!(f, "ViewHistory"),
81 Self::CreateSnapshot => write!(f, "CreateSnapshot"),
82 Self::RestoreSnapshot => write!(f, "RestoreSnapshot"),
83 Self::ManageSettings => write!(f, "ManageSettings"),
84 Self::ManageIntegrations => write!(f, "ManageIntegrations"),
85 Self::ScenarioModifyChaosRules => write!(f, "ScenarioModifyChaosRules"),
86 Self::ScenarioModifyRealityDefaults => write!(f, "ScenarioModifyRealityDefaults"),
87 Self::ScenarioPromote => write!(f, "ScenarioPromote"),
88 Self::ScenarioApprove => write!(f, "ScenarioApprove"),
89 Self::ScenarioModifyDriftBudgets => write!(f, "ScenarioModifyDriftBudgets"),
90 }
91 }
92}
93
94pub struct RolePermissions;
96
97impl RolePermissions {
98 #[must_use]
100 pub fn get_permissions(role: UserRole) -> Vec<Permission> {
101 match role {
102 UserRole::Admin => vec![
103 Permission::WorkspaceCreate,
105 Permission::WorkspaceRead,
106 Permission::WorkspaceUpdate,
107 Permission::WorkspaceDelete,
108 Permission::WorkspaceArchive,
109 Permission::WorkspaceManageMembers,
110 Permission::MockCreate,
111 Permission::MockRead,
112 Permission::MockUpdate,
113 Permission::MockDelete,
114 Permission::InviteMembers,
115 Permission::RemoveMembers,
116 Permission::ChangeRoles,
117 Permission::ViewHistory,
118 Permission::CreateSnapshot,
119 Permission::RestoreSnapshot,
120 Permission::ManageSettings,
121 Permission::ManageIntegrations,
122 Permission::ScenarioModifyChaosRules,
124 Permission::ScenarioModifyRealityDefaults,
125 Permission::ScenarioPromote,
126 Permission::ScenarioApprove,
127 Permission::ScenarioModifyDriftBudgets,
128 ],
129 UserRole::Editor => vec![
130 Permission::WorkspaceRead,
132 Permission::MockCreate,
133 Permission::MockRead,
134 Permission::MockUpdate,
135 Permission::MockDelete,
136 Permission::ViewHistory,
137 Permission::CreateSnapshot,
138 Permission::ScenarioPromote,
140 ],
141 UserRole::Viewer => vec![
142 Permission::WorkspaceRead,
144 Permission::MockRead,
145 Permission::ViewHistory,
146 ],
147 }
148 }
149
150 #[must_use]
152 pub fn has_permission(role: UserRole, permission: Permission) -> bool {
153 Self::get_permissions(role).contains(&permission)
154 }
155}
156
157pub struct PermissionChecker;
159
160impl PermissionChecker {
161 pub fn check(user_role: UserRole, required_permission: Permission) -> Result<()> {
167 if RolePermissions::has_permission(user_role, required_permission) {
168 Ok(())
169 } else {
170 Err(CollabError::AuthorizationFailed(format!(
171 "Role {user_role:?} does not have permission {required_permission:?}"
172 )))
173 }
174 }
175
176 pub fn check_all(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
182 for permission in required_permissions {
183 Self::check(user_role, *permission)?;
184 }
185 Ok(())
186 }
187
188 pub fn check_any(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
194 for permission in required_permissions {
195 if RolePermissions::has_permission(user_role, *permission) {
196 return Ok(());
197 }
198 }
199 Err(CollabError::AuthorizationFailed(format!(
200 "Role {user_role:?} does not have any of the required permissions"
201 )))
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_admin_permissions() {
211 let permissions = RolePermissions::get_permissions(UserRole::Admin);
212 assert!(permissions.contains(&Permission::WorkspaceDelete));
213 assert!(permissions.contains(&Permission::MockCreate));
214 assert!(permissions.contains(&Permission::ChangeRoles));
215 }
216
217 #[test]
218 fn test_editor_permissions() {
219 let permissions = RolePermissions::get_permissions(UserRole::Editor);
220 assert!(permissions.contains(&Permission::MockCreate));
221 assert!(permissions.contains(&Permission::MockUpdate));
222 assert!(!permissions.contains(&Permission::WorkspaceDelete));
223 assert!(!permissions.contains(&Permission::ChangeRoles));
224 }
225
226 #[test]
227 fn test_viewer_permissions() {
228 let permissions = RolePermissions::get_permissions(UserRole::Viewer);
229 assert!(permissions.contains(&Permission::WorkspaceRead));
230 assert!(permissions.contains(&Permission::MockRead));
231 assert!(!permissions.contains(&Permission::MockCreate));
232 assert!(!permissions.contains(&Permission::MockUpdate));
233 }
234
235 #[test]
236 fn test_permission_check() {
237 assert!(PermissionChecker::check(UserRole::Admin, Permission::WorkspaceDelete).is_ok());
238 assert!(PermissionChecker::check(UserRole::Editor, Permission::MockCreate).is_ok());
239 assert!(PermissionChecker::check(UserRole::Viewer, Permission::MockCreate).is_err());
240 }
241
242 #[test]
243 fn test_check_all() {
244 let permissions = vec![Permission::MockRead, Permission::MockCreate];
245 assert!(PermissionChecker::check_all(UserRole::Editor, &permissions).is_ok());
246 assert!(PermissionChecker::check_all(UserRole::Viewer, &permissions).is_err());
247 }
248
249 #[test]
250 fn test_check_any() {
251 let permissions = vec![Permission::MockCreate, Permission::WorkspaceDelete];
252 assert!(PermissionChecker::check_any(UserRole::Editor, &permissions).is_ok());
253
254 let admin_only = vec![Permission::WorkspaceDelete, Permission::ChangeRoles];
255 assert!(PermissionChecker::check_any(UserRole::Viewer, &admin_only).is_err());
256 }
257}