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,
13 WorkspaceUpdate,
14 WorkspaceDelete,
15 WorkspaceArchive,
16 WorkspaceManageMembers,
17
18 MockCreate,
20 MockRead,
21 MockUpdate,
22 MockDelete,
23
24 InviteMembers,
26 RemoveMembers,
27 ChangeRoles,
28
29 ViewHistory,
31 CreateSnapshot,
32 RestoreSnapshot,
33
34 ManageSettings,
36 ManageIntegrations,
37
38 ScenarioModifyChaosRules,
41 ScenarioModifyRealityDefaults,
43 ScenarioPromote,
45 ScenarioApprove,
47 ScenarioModifyDriftBudgets,
49}
50
51impl std::fmt::Display for Permission {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 Self::WorkspaceCreate => write!(f, "WorkspaceCreate"),
55 Self::WorkspaceRead => write!(f, "WorkspaceRead"),
56 Self::WorkspaceUpdate => write!(f, "WorkspaceUpdate"),
57 Self::WorkspaceDelete => write!(f, "WorkspaceDelete"),
58 Self::WorkspaceArchive => write!(f, "WorkspaceArchive"),
59 Self::WorkspaceManageMembers => write!(f, "WorkspaceManageMembers"),
60 Self::MockCreate => write!(f, "MockCreate"),
61 Self::MockRead => write!(f, "MockRead"),
62 Self::MockUpdate => write!(f, "MockUpdate"),
63 Self::MockDelete => write!(f, "MockDelete"),
64 Self::InviteMembers => write!(f, "InviteMembers"),
65 Self::RemoveMembers => write!(f, "RemoveMembers"),
66 Self::ChangeRoles => write!(f, "ChangeRoles"),
67 Self::ViewHistory => write!(f, "ViewHistory"),
68 Self::CreateSnapshot => write!(f, "CreateSnapshot"),
69 Self::RestoreSnapshot => write!(f, "RestoreSnapshot"),
70 Self::ManageSettings => write!(f, "ManageSettings"),
71 Self::ManageIntegrations => write!(f, "ManageIntegrations"),
72 Self::ScenarioModifyChaosRules => write!(f, "ScenarioModifyChaosRules"),
73 Self::ScenarioModifyRealityDefaults => write!(f, "ScenarioModifyRealityDefaults"),
74 Self::ScenarioPromote => write!(f, "ScenarioPromote"),
75 Self::ScenarioApprove => write!(f, "ScenarioApprove"),
76 Self::ScenarioModifyDriftBudgets => write!(f, "ScenarioModifyDriftBudgets"),
77 }
78 }
79}
80
81pub struct RolePermissions;
83
84impl RolePermissions {
85 #[must_use]
87 pub fn get_permissions(role: UserRole) -> Vec<Permission> {
88 match role {
89 UserRole::Admin => vec![
90 Permission::WorkspaceCreate,
92 Permission::WorkspaceRead,
93 Permission::WorkspaceUpdate,
94 Permission::WorkspaceDelete,
95 Permission::WorkspaceArchive,
96 Permission::WorkspaceManageMembers,
97 Permission::MockCreate,
98 Permission::MockRead,
99 Permission::MockUpdate,
100 Permission::MockDelete,
101 Permission::InviteMembers,
102 Permission::RemoveMembers,
103 Permission::ChangeRoles,
104 Permission::ViewHistory,
105 Permission::CreateSnapshot,
106 Permission::RestoreSnapshot,
107 Permission::ManageSettings,
108 Permission::ManageIntegrations,
109 Permission::ScenarioModifyChaosRules,
111 Permission::ScenarioModifyRealityDefaults,
112 Permission::ScenarioPromote,
113 Permission::ScenarioApprove,
114 Permission::ScenarioModifyDriftBudgets,
115 ],
116 UserRole::Editor => vec![
117 Permission::WorkspaceRead,
119 Permission::MockCreate,
120 Permission::MockRead,
121 Permission::MockUpdate,
122 Permission::MockDelete,
123 Permission::ViewHistory,
124 Permission::CreateSnapshot,
125 Permission::ScenarioPromote,
127 ],
128 UserRole::Viewer => vec![
129 Permission::WorkspaceRead,
131 Permission::MockRead,
132 Permission::ViewHistory,
133 ],
134 }
135 }
136
137 #[must_use]
139 pub fn has_permission(role: UserRole, permission: Permission) -> bool {
140 Self::get_permissions(role).contains(&permission)
141 }
142}
143
144pub struct PermissionChecker;
146
147impl PermissionChecker {
148 pub fn check(user_role: UserRole, required_permission: Permission) -> Result<()> {
150 if RolePermissions::has_permission(user_role, required_permission) {
151 Ok(())
152 } else {
153 Err(CollabError::AuthorizationFailed(format!(
154 "Role {user_role:?} does not have permission {required_permission:?}"
155 )))
156 }
157 }
158
159 pub fn check_all(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
161 for permission in required_permissions {
162 Self::check(user_role, *permission)?;
163 }
164 Ok(())
165 }
166
167 pub fn check_any(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
169 for permission in required_permissions {
170 if RolePermissions::has_permission(user_role, *permission) {
171 return Ok(());
172 }
173 }
174 Err(CollabError::AuthorizationFailed(format!(
175 "Role {user_role:?} does not have any of the required permissions"
176 )))
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_admin_permissions() {
186 let permissions = RolePermissions::get_permissions(UserRole::Admin);
187 assert!(permissions.contains(&Permission::WorkspaceDelete));
188 assert!(permissions.contains(&Permission::MockCreate));
189 assert!(permissions.contains(&Permission::ChangeRoles));
190 }
191
192 #[test]
193 fn test_editor_permissions() {
194 let permissions = RolePermissions::get_permissions(UserRole::Editor);
195 assert!(permissions.contains(&Permission::MockCreate));
196 assert!(permissions.contains(&Permission::MockUpdate));
197 assert!(!permissions.contains(&Permission::WorkspaceDelete));
198 assert!(!permissions.contains(&Permission::ChangeRoles));
199 }
200
201 #[test]
202 fn test_viewer_permissions() {
203 let permissions = RolePermissions::get_permissions(UserRole::Viewer);
204 assert!(permissions.contains(&Permission::WorkspaceRead));
205 assert!(permissions.contains(&Permission::MockRead));
206 assert!(!permissions.contains(&Permission::MockCreate));
207 assert!(!permissions.contains(&Permission::MockUpdate));
208 }
209
210 #[test]
211 fn test_permission_check() {
212 assert!(PermissionChecker::check(UserRole::Admin, Permission::WorkspaceDelete).is_ok());
213 assert!(PermissionChecker::check(UserRole::Editor, Permission::MockCreate).is_ok());
214 assert!(PermissionChecker::check(UserRole::Viewer, Permission::MockCreate).is_err());
215 }
216
217 #[test]
218 fn test_check_all() {
219 let permissions = vec![Permission::MockRead, Permission::MockCreate];
220 assert!(PermissionChecker::check_all(UserRole::Editor, &permissions).is_ok());
221 assert!(PermissionChecker::check_all(UserRole::Viewer, &permissions).is_err());
222 }
223
224 #[test]
225 fn test_check_any() {
226 let permissions = vec![Permission::MockCreate, Permission::WorkspaceDelete];
227 assert!(PermissionChecker::check_any(UserRole::Editor, &permissions).is_ok());
228
229 let admin_only = vec![Permission::WorkspaceDelete, Permission::ChangeRoles];
230 assert!(PermissionChecker::check_any(UserRole::Viewer, &admin_only).is_err());
231 }
232}