use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Permission {
Read,
Write,
Update,
Delete,
Share,
Admin,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ResourceType {
Memory,
CrossRef,
Tag,
Namespace,
User,
ApiKey,
System,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PermissionSet {
permissions: HashSet<(Permission, ResourceType)>,
is_admin: bool,
}
impl PermissionSet {
pub fn new() -> Self {
Self::default()
}
pub fn from_permissions(perms: Vec<(Permission, ResourceType)>) -> Self {
Self {
permissions: perms.into_iter().collect(),
is_admin: false,
}
}
pub fn admin() -> Self {
Self {
permissions: HashSet::new(),
is_admin: true,
}
}
pub fn read_only() -> Self {
let mut permissions = HashSet::new();
permissions.insert((Permission::Read, ResourceType::Memory));
permissions.insert((Permission::Read, ResourceType::CrossRef));
permissions.insert((Permission::Read, ResourceType::Tag));
Self {
permissions,
is_admin: false,
}
}
pub fn standard_user() -> Self {
let resources = [
ResourceType::Memory,
ResourceType::CrossRef,
ResourceType::Tag,
];
let permissions = [
Permission::Read,
Permission::Write,
Permission::Update,
Permission::Delete,
];
let mut set = HashSet::new();
for resource in resources {
for permission in permissions {
set.insert((permission, resource));
}
}
set.insert((Permission::Read, ResourceType::ApiKey));
set.insert((Permission::Write, ResourceType::ApiKey));
set.insert((Permission::Delete, ResourceType::ApiKey));
Self {
permissions: set,
is_admin: false,
}
}
pub fn add(&mut self, permission: Permission, resource: ResourceType) {
self.permissions.insert((permission, resource));
}
pub fn remove(&mut self, permission: Permission, resource: ResourceType) {
self.permissions.remove(&(permission, resource));
}
pub fn has_permission(&self, permission: Permission, resource: ResourceType) -> bool {
if self.is_admin {
return true;
}
self.permissions.contains(&(permission, resource))
}
pub fn is_admin(&self) -> bool {
self.is_admin
}
pub fn merge(&mut self, other: &PermissionSet) {
if other.is_admin {
self.is_admin = true;
}
self.permissions.extend(other.permissions.iter().cloned());
}
pub fn to_vec(&self) -> Vec<(Permission, ResourceType)> {
self.permissions.iter().cloned().collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_permission_set_basic() {
let mut set = PermissionSet::new();
set.add(Permission::Read, ResourceType::Memory);
assert!(set.has_permission(Permission::Read, ResourceType::Memory));
assert!(!set.has_permission(Permission::Write, ResourceType::Memory));
assert!(!set.has_permission(Permission::Read, ResourceType::User));
}
#[test]
fn test_admin_set() {
let set = PermissionSet::admin();
assert!(set.has_permission(Permission::Admin, ResourceType::System));
assert!(set.has_permission(Permission::Delete, ResourceType::User));
assert!(set.has_permission(Permission::Read, ResourceType::Memory));
}
#[test]
fn test_standard_user() {
let set = PermissionSet::standard_user();
assert!(set.has_permission(Permission::Read, ResourceType::Memory));
assert!(set.has_permission(Permission::Write, ResourceType::Memory));
assert!(set.has_permission(Permission::Delete, ResourceType::Memory));
assert!(!set.has_permission(Permission::Admin, ResourceType::System));
assert!(!set.has_permission(Permission::Delete, ResourceType::User));
}
#[test]
fn test_merge() {
let mut set1 = PermissionSet::new();
set1.add(Permission::Read, ResourceType::Memory);
let mut set2 = PermissionSet::new();
set2.add(Permission::Write, ResourceType::Memory);
set1.merge(&set2);
assert!(set1.has_permission(Permission::Read, ResourceType::Memory));
assert!(set1.has_permission(Permission::Write, ResourceType::Memory));
}
#[test]
fn test_serialization() {
let set = PermissionSet::standard_user();
let json = serde_json::to_string(&set).unwrap();
let restored: PermissionSet = serde_json::from_str(&json).unwrap();
assert!(restored.has_permission(Permission::Read, ResourceType::Memory));
assert!(restored.has_permission(Permission::Write, ResourceType::Memory));
}
}