use crate::error::{CollabError, Result};
use crate::models::UserRole;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum Permission {
WorkspaceCreate,
WorkspaceRead,
WorkspaceUpdate,
WorkspaceDelete,
WorkspaceArchive,
WorkspaceManageMembers,
MockCreate,
MockRead,
MockUpdate,
MockDelete,
InviteMembers,
RemoveMembers,
ChangeRoles,
ViewHistory,
CreateSnapshot,
RestoreSnapshot,
ManageSettings,
ManageIntegrations,
ScenarioModifyChaosRules,
ScenarioModifyRealityDefaults,
ScenarioPromote,
ScenarioApprove,
ScenarioModifyDriftBudgets,
}
impl std::fmt::Display for Permission {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::WorkspaceCreate => write!(f, "WorkspaceCreate"),
Self::WorkspaceRead => write!(f, "WorkspaceRead"),
Self::WorkspaceUpdate => write!(f, "WorkspaceUpdate"),
Self::WorkspaceDelete => write!(f, "WorkspaceDelete"),
Self::WorkspaceArchive => write!(f, "WorkspaceArchive"),
Self::WorkspaceManageMembers => write!(f, "WorkspaceManageMembers"),
Self::MockCreate => write!(f, "MockCreate"),
Self::MockRead => write!(f, "MockRead"),
Self::MockUpdate => write!(f, "MockUpdate"),
Self::MockDelete => write!(f, "MockDelete"),
Self::InviteMembers => write!(f, "InviteMembers"),
Self::RemoveMembers => write!(f, "RemoveMembers"),
Self::ChangeRoles => write!(f, "ChangeRoles"),
Self::ViewHistory => write!(f, "ViewHistory"),
Self::CreateSnapshot => write!(f, "CreateSnapshot"),
Self::RestoreSnapshot => write!(f, "RestoreSnapshot"),
Self::ManageSettings => write!(f, "ManageSettings"),
Self::ManageIntegrations => write!(f, "ManageIntegrations"),
Self::ScenarioModifyChaosRules => write!(f, "ScenarioModifyChaosRules"),
Self::ScenarioModifyRealityDefaults => write!(f, "ScenarioModifyRealityDefaults"),
Self::ScenarioPromote => write!(f, "ScenarioPromote"),
Self::ScenarioApprove => write!(f, "ScenarioApprove"),
Self::ScenarioModifyDriftBudgets => write!(f, "ScenarioModifyDriftBudgets"),
}
}
}
pub struct RolePermissions;
impl RolePermissions {
#[must_use]
pub fn get_permissions(role: UserRole) -> Vec<Permission> {
match role {
UserRole::Admin => vec![
Permission::WorkspaceCreate,
Permission::WorkspaceRead,
Permission::WorkspaceUpdate,
Permission::WorkspaceDelete,
Permission::WorkspaceArchive,
Permission::WorkspaceManageMembers,
Permission::MockCreate,
Permission::MockRead,
Permission::MockUpdate,
Permission::MockDelete,
Permission::InviteMembers,
Permission::RemoveMembers,
Permission::ChangeRoles,
Permission::ViewHistory,
Permission::CreateSnapshot,
Permission::RestoreSnapshot,
Permission::ManageSettings,
Permission::ManageIntegrations,
Permission::ScenarioModifyChaosRules,
Permission::ScenarioModifyRealityDefaults,
Permission::ScenarioPromote,
Permission::ScenarioApprove,
Permission::ScenarioModifyDriftBudgets,
],
UserRole::Editor => vec![
Permission::WorkspaceRead,
Permission::MockCreate,
Permission::MockRead,
Permission::MockUpdate,
Permission::MockDelete,
Permission::ViewHistory,
Permission::CreateSnapshot,
Permission::ScenarioPromote,
],
UserRole::Viewer => vec![
Permission::WorkspaceRead,
Permission::MockRead,
Permission::ViewHistory,
],
}
}
#[must_use]
pub fn has_permission(role: UserRole, permission: Permission) -> bool {
Self::get_permissions(role).contains(&permission)
}
}
pub struct PermissionChecker;
impl PermissionChecker {
pub fn check(user_role: UserRole, required_permission: Permission) -> Result<()> {
if RolePermissions::has_permission(user_role, required_permission) {
Ok(())
} else {
Err(CollabError::AuthorizationFailed(format!(
"Role {user_role:?} does not have permission {required_permission:?}"
)))
}
}
pub fn check_all(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
for permission in required_permissions {
Self::check(user_role, *permission)?;
}
Ok(())
}
pub fn check_any(user_role: UserRole, required_permissions: &[Permission]) -> Result<()> {
for permission in required_permissions {
if RolePermissions::has_permission(user_role, *permission) {
return Ok(());
}
}
Err(CollabError::AuthorizationFailed(format!(
"Role {user_role:?} does not have any of the required permissions"
)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_admin_permissions() {
let permissions = RolePermissions::get_permissions(UserRole::Admin);
assert!(permissions.contains(&Permission::WorkspaceDelete));
assert!(permissions.contains(&Permission::MockCreate));
assert!(permissions.contains(&Permission::ChangeRoles));
}
#[test]
fn test_editor_permissions() {
let permissions = RolePermissions::get_permissions(UserRole::Editor);
assert!(permissions.contains(&Permission::MockCreate));
assert!(permissions.contains(&Permission::MockUpdate));
assert!(!permissions.contains(&Permission::WorkspaceDelete));
assert!(!permissions.contains(&Permission::ChangeRoles));
}
#[test]
fn test_viewer_permissions() {
let permissions = RolePermissions::get_permissions(UserRole::Viewer);
assert!(permissions.contains(&Permission::WorkspaceRead));
assert!(permissions.contains(&Permission::MockRead));
assert!(!permissions.contains(&Permission::MockCreate));
assert!(!permissions.contains(&Permission::MockUpdate));
}
#[test]
fn test_permission_check() {
assert!(PermissionChecker::check(UserRole::Admin, Permission::WorkspaceDelete).is_ok());
assert!(PermissionChecker::check(UserRole::Editor, Permission::MockCreate).is_ok());
assert!(PermissionChecker::check(UserRole::Viewer, Permission::MockCreate).is_err());
}
#[test]
fn test_check_all() {
let permissions = vec![Permission::MockRead, Permission::MockCreate];
assert!(PermissionChecker::check_all(UserRole::Editor, &permissions).is_ok());
assert!(PermissionChecker::check_all(UserRole::Viewer, &permissions).is_err());
}
#[test]
fn test_check_any() {
let permissions = vec![Permission::MockCreate, Permission::WorkspaceDelete];
assert!(PermissionChecker::check_any(UserRole::Editor, &permissions).is_ok());
let admin_only = vec![Permission::WorkspaceDelete, Permission::ChangeRoles];
assert!(PermissionChecker::check_any(UserRole::Viewer, &admin_only).is_err());
}
}