use std::collections::BTreeSet;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Permission {
Read,
Write,
Ddl,
Admin,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Role {
pub name: String,
pub permissions: BTreeSet<Permission>,
}
impl Role {
pub fn allows(&self, p: Permission) -> bool {
self.permissions.contains(&p)
}
pub fn admin() -> Role {
Role {
name: "admin".to_string(),
permissions: BTreeSet::from([
Permission::Read,
Permission::Write,
Permission::Ddl,
Permission::Admin,
]),
}
}
pub fn readwrite() -> Role {
Role {
name: "readwrite".to_string(),
permissions: BTreeSet::from([Permission::Read, Permission::Write]),
}
}
pub fn readonly() -> Role {
Role {
name: "readonly".to_string(),
permissions: BTreeSet::from([Permission::Read]),
}
}
pub fn builtin(name: &str) -> Option<Role> {
match name {
"admin" => Some(Role::admin()),
"readwrite" => Some(Role::readwrite()),
"readonly" => Some(Role::readonly()),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn admin_has_all_permissions() {
let r = Role::admin();
assert_eq!(
r.permissions,
BTreeSet::from([
Permission::Read,
Permission::Write,
Permission::Ddl,
Permission::Admin,
])
);
}
#[test]
fn admin_allows_everything() {
let r = Role::admin();
for p in [
Permission::Read,
Permission::Write,
Permission::Ddl,
Permission::Admin,
] {
assert!(r.allows(p));
}
}
#[test]
fn readwrite_has_read_and_write_only() {
let r = Role::readwrite();
assert_eq!(
r.permissions,
BTreeSet::from([Permission::Read, Permission::Write])
);
assert!(r.allows(Permission::Read));
assert!(r.allows(Permission::Write));
assert!(!r.allows(Permission::Ddl));
assert!(!r.allows(Permission::Admin));
}
#[test]
fn readonly_has_read_only() {
let r = Role::readonly();
assert_eq!(r.permissions, BTreeSet::from([Permission::Read]));
assert!(r.allows(Permission::Read));
assert!(!r.allows(Permission::Write));
assert!(!r.allows(Permission::Ddl));
assert!(!r.allows(Permission::Admin));
}
#[test]
fn builtin_resolves_known_roles() {
assert_eq!(Role::builtin("admin").unwrap().name, "admin");
assert_eq!(Role::builtin("readwrite").unwrap().name, "readwrite");
assert_eq!(Role::builtin("readonly").unwrap().name, "readonly");
}
#[test]
fn builtin_unknown_is_none() {
assert!(Role::builtin("nope").is_none());
}
}