daemon/src/models/user.rs

196 lines
4.9 KiB
Rust

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<u64>,
}
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<Option<User>, 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<u64> {
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<u64>,
pub permissions: HashMap<u64, Permissions>,
id: Option<u64>,
}
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<Option<Self>, 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<Self, j_db::error::JDbError> {
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<Self, j_db::error::JDbError> {
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<Vec<UserGroup>, 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<bool, j_db::error::JDbError> {
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<UserGroup>,
service_group: Vec<ServiceGroup>,
) -> bool {
let mut unified_permission_map: HashMap<u64, Permissions> = 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<u64> = 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<u64> {
self.id
}
fn set_id(&mut self, id: u64) {
self.id = Some(id);
}
fn tree() -> String {
"UserGroup".to_string()
}
}