use crate::models::service::ServiceGroup; use bitflags::bitflags; use j_db::database::Database; use j_db::model::JdbModel; use poise::serenity_prelude::UserId; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct User { pub discord_uuid: UserId, id: Option, } impl User { pub fn new(discord_uuid: UserId) -> Self { Self { discord_uuid, id: None, } } pub fn find_user_by_id( db: &Database, uuid: UserId, ) -> Result, j_db::error::JDbError> { let user = db .filter(|_, user: &User| user.discord_uuid == uuid)? .next(); Ok(user) } } impl j_db::model::JdbModel for User { fn id(&self) -> Option { self.id } fn set_id(&mut self, id: u64) { self.id = Some(id); } fn tree() -> String { "User".to_string() } } bitflags! { #[derive(Serialize, Deserialize, Copy, Debug, Clone, PartialEq)] pub struct Permissions: u32 { const Status = 0b00001; const Start = 0b00010; const Stop = 0b00100; const Restart = 0b01000; } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UserGroup { pub name: String, pub description: String, pub members: HashSet, pub permissions: HashMap, id: Option, } impl UserGroup { pub fn new(name: &str, description: &str) -> Self { Self { name: name.to_string(), description: description.to_string(), members: HashSet::new(), permissions: Default::default(), id: None, } } pub fn find_group_by_name( db: &Database, name: &str, ) -> Result, j_db::error::JDbError> { let group = db .filter(|_, group: &UserGroup| group.name.eq_ignore_ascii_case(name))? .next(); Ok(group) } pub fn add_user_to_group( db: &Database, group_name: &str, user_id: u64, ) -> Result { let mut group = Self::find_group_by_name(db, group_name)?.ok_or(j_db::error::JDbError::NotFound)?; group.members.insert(user_id); let group = db.insert(group)?; Ok(group) } pub fn set_group_permission( db: &Database, group_name: &str, service_group: u64, permissions: Permissions, ) -> Result { let mut group = Self::find_group_by_name(db, group_name)?.ok_or(j_db::error::JDbError::NotFound)?; group.permissions.insert(service_group, permissions); let group = db.insert(group)?; Ok(group) } pub fn get_user_groups( db: &Database, user: u64, ) -> Result, j_db::error::JDbError> { Ok(db .filter(|_, group: &UserGroup| group.members.contains(&user))? .collect()) } pub fn check_if_user_has_permission( db: &Database, user: u64, service: u64, permission: Permissions, ) -> Result { let user_groups = Self::get_user_groups(db, user)?; let service_group = ServiceGroup::get_service_groups(db, service)?; Ok(Self::check_perm(permission, user_groups, service_group)) } fn check_perm( permission: Permissions, user_groups: Vec, service_group: Vec, ) -> bool { let mut unified_permission_map: HashMap = HashMap::new(); for user_group in user_groups { for (group, permission) in user_group.permissions { #[allow(clippy::map_entry)] if unified_permission_map.contains_key(&group) { let perm1 = unified_permission_map.get_mut(&group).unwrap(); *perm1 |= permission; } else { unified_permission_map.insert(group, permission); } } } let service_group_ids: HashSet = service_group .iter() .map(|service_group| service_group.id().unwrap()) .collect(); for service_group in service_group_ids { let perm = unified_permission_map.get(&service_group); if let Some(perm) = perm { let check_perm = (permission & *perm) == permission; if check_perm { return true; } } } false } } impl JdbModel for UserGroup { fn id(&self) -> Option { self.id } fn set_id(&mut self, id: u64) { self.id = Some(id); } fn tree() -> String { "UserGroup".to_string() } }