#[derive(Debug, Clone, serde::Serialize)]
pub struct ResourcePermissions {
pub list: Vec<String>,
pub view: Vec<String>,
pub create: Vec<String>,
pub edit: Vec<String>,
pub delete: Vec<String>,
}
impl ResourcePermissions {
pub fn uniform(roles: Vec<String>) -> Self {
Self {
list: roles.clone(),
view: roles.clone(),
create: roles.clone(),
edit: roles.clone(),
delete: roles,
}
}
pub fn can(&self, operation: CrudOperation, role: &str) -> bool {
let allowed = match operation {
CrudOperation::List => &self.list,
CrudOperation::View => &self.view,
CrudOperation::Create => &self.create,
CrudOperation::Edit => &self.edit,
CrudOperation::Delete => &self.delete,
};
allowed.iter().any(|r| r == role)
}
pub fn can_any(&self, operation: CrudOperation, roles: &[&str]) -> bool {
roles.iter().any(|role| self.can(operation, role))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub enum CrudOperation {
List,
View,
Create,
Edit,
Delete,
}
#[derive(Debug, Clone, Default, serde::Serialize)]
pub enum ColumnFilter {
#[default]
All,
Include(Vec<String>),
Exclude(Vec<String>),
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct DisplayConfig {
pub icon: Option<String>,
pub columns: ColumnFilter,
pub pagination: usize,
}
impl DisplayConfig {
pub fn new() -> Self {
Self {
icon: None,
columns: ColumnFilter::All,
pagination: 25,
}
}
pub fn icon(mut self, icon: &str) -> Self {
self.icon = Some(icon.to_string());
self
}
pub fn pagination(mut self, per_page: usize) -> Self {
self.pagination = per_page;
self
}
pub fn columns_include(mut self, cols: Vec<&str>) -> Self {
self.columns = ColumnFilter::Include(cols.iter().map(|s| s.to_string()).collect());
self
}
pub fn columns_exclude(mut self, cols: Vec<&str>) -> Self {
self.columns = ColumnFilter::Exclude(cols.iter().map(|s| s.to_string()).collect());
self
}
}
impl Default for DisplayConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct AdminResource {
pub key: &'static str,
pub model_path: &'static str,
pub form_path: &'static str,
pub title: &'static str,
pub permissions: ResourcePermissions,
pub display: DisplayConfig,
}
impl AdminResource {
pub fn new(
key: &'static str,
model_path: &'static str,
form_path: &'static str,
title: &'static str,
roles: Vec<String>,
) -> Self {
Self {
key,
model_path,
form_path,
title,
permissions: ResourcePermissions::uniform(roles),
display: DisplayConfig::new(),
}
}
pub fn with_permissions(
key: &'static str,
model_path: &'static str,
form_path: &'static str,
title: &'static str,
permissions: ResourcePermissions,
) -> Self {
Self {
key,
model_path,
form_path,
title,
permissions,
display: DisplayConfig::new(),
}
}
pub fn display(mut self, display: DisplayConfig) -> Self {
self.display = display;
self
}
pub fn list_route(&self) -> String {
format!("/{}/list", self.key)
}
pub fn create_route(&self) -> String {
format!("/{}/create", self.key)
}
pub fn detail_route(&self) -> String {
format!("/{}/{{id}}", self.key)
}
pub fn delete_route(&self) -> String {
format!("/{}/{{id}}/delete", self.key)
}
}