mockforge_collab/
permissions.rs

1//! Permission checking and role-based access control
2
3use crate::error::{CollabError, Result};
4use crate::models::UserRole;
5use serde::{Deserialize, Serialize};
6
7/// Permission types in the system
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
9pub enum Permission {
10    // Workspace permissions
11    WorkspaceCreate,
12    WorkspaceRead,
13    WorkspaceUpdate,
14    WorkspaceDelete,
15    WorkspaceArchive,
16    WorkspaceManageMembers,
17
18    // Mock/Route permissions
19    MockCreate,
20    MockRead,
21    MockUpdate,
22    MockDelete,
23
24    // Collaboration permissions
25    InviteMembers,
26    RemoveMembers,
27    ChangeRoles,
28
29    // History permissions
30    ViewHistory,
31    CreateSnapshot,
32    RestoreSnapshot,
33
34    // Settings permissions
35    ManageSettings,
36    ManageIntegrations,
37}
38
39/// Role permissions mapping
40pub struct RolePermissions;
41
42impl RolePermissions {
43    /// Get all permissions for a role
44    pub fn get_permissions(role: UserRole) -> Vec<Permission> {
45        match role {
46            UserRole::Admin => vec![
47                // Full access to everything
48                Permission::WorkspaceCreate,
49                Permission::WorkspaceRead,
50                Permission::WorkspaceUpdate,
51                Permission::WorkspaceDelete,
52                Permission::WorkspaceArchive,
53                Permission::WorkspaceManageMembers,
54                Permission::MockCreate,
55                Permission::MockRead,
56                Permission::MockUpdate,
57                Permission::MockDelete,
58                Permission::InviteMembers,
59                Permission::RemoveMembers,
60                Permission::ChangeRoles,
61                Permission::ViewHistory,
62                Permission::CreateSnapshot,
63                Permission::RestoreSnapshot,
64                Permission::ManageSettings,
65                Permission::ManageIntegrations,
66            ],
67            UserRole::Editor => vec![
68                // Can edit but not manage workspace or members
69                Permission::WorkspaceRead,
70                Permission::MockCreate,
71                Permission::MockRead,
72                Permission::MockUpdate,
73                Permission::MockDelete,
74                Permission::ViewHistory,
75                Permission::CreateSnapshot,
76            ],
77            UserRole::Viewer => vec![
78                // Read-only access
79                Permission::WorkspaceRead,
80                Permission::MockRead,
81                Permission::ViewHistory,
82            ],
83        }
84    }
85
86    /// Check if a role has a specific permission
87    pub fn has_permission(role: UserRole, permission: Permission) -> bool {
88        Self::get_permissions(role).contains(&permission)
89    }
90}
91
92/// Permission checker for authorization
93pub struct PermissionChecker;
94
95impl PermissionChecker {
96    /// Check if a user has permission to perform an action
97    pub fn check(user_role: UserRole, required_permission: Permission) -> Result<()> {
98        if RolePermissions::has_permission(user_role, required_permission) {
99            Ok(())
100        } else {
101            Err(CollabError::AuthorizationFailed(format!(
102                "Role {:?} does not have permission {:?}",
103                user_role, required_permission
104            )))
105        }
106    }
107
108    /// Check multiple permissions (must have all)
109    pub fn check_all(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
110        for permission in required_permissions {
111            Self::check(user_role, *permission)?;
112        }
113        Ok(())
114    }
115
116    /// Check multiple permissions (must have at least one)
117    pub fn check_any(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
118        for permission in required_permissions {
119            if RolePermissions::has_permission(user_role, *permission) {
120                return Ok(());
121            }
122        }
123        Err(CollabError::AuthorizationFailed(format!(
124            "Role {:?} does not have any of the required permissions",
125            user_role
126        )))
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn test_admin_permissions() {
136        let permissions = RolePermissions::get_permissions(UserRole::Admin);
137        assert!(permissions.contains(&Permission::WorkspaceDelete));
138        assert!(permissions.contains(&Permission::MockCreate));
139        assert!(permissions.contains(&Permission::ChangeRoles));
140    }
141
142    #[test]
143    fn test_editor_permissions() {
144        let permissions = RolePermissions::get_permissions(UserRole::Editor);
145        assert!(permissions.contains(&Permission::MockCreate));
146        assert!(permissions.contains(&Permission::MockUpdate));
147        assert!(!permissions.contains(&Permission::WorkspaceDelete));
148        assert!(!permissions.contains(&Permission::ChangeRoles));
149    }
150
151    #[test]
152    fn test_viewer_permissions() {
153        let permissions = RolePermissions::get_permissions(UserRole::Viewer);
154        assert!(permissions.contains(&Permission::WorkspaceRead));
155        assert!(permissions.contains(&Permission::MockRead));
156        assert!(!permissions.contains(&Permission::MockCreate));
157        assert!(!permissions.contains(&Permission::MockUpdate));
158    }
159
160    #[test]
161    fn test_permission_check() {
162        assert!(PermissionChecker::check(UserRole::Admin, Permission::WorkspaceDelete).is_ok());
163        assert!(PermissionChecker::check(UserRole::Editor, Permission::MockCreate).is_ok());
164        assert!(PermissionChecker::check(UserRole::Viewer, Permission::MockCreate).is_err());
165    }
166
167    #[test]
168    fn test_check_all() {
169        let permissions = vec![Permission::MockRead, Permission::MockCreate];
170        assert!(PermissionChecker::check_all(UserRole::Editor, &permissions).is_ok());
171        assert!(PermissionChecker::check_all(UserRole::Viewer, &permissions).is_err());
172    }
173
174    #[test]
175    fn test_check_any() {
176        let permissions = vec![Permission::MockCreate, Permission::WorkspaceDelete];
177        assert!(PermissionChecker::check_any(UserRole::Editor, &permissions).is_ok());
178
179        let admin_only = vec![Permission::WorkspaceDelete, Permission::ChangeRoles];
180        assert!(PermissionChecker::check_any(UserRole::Viewer, &admin_only).is_err());
181    }
182}