use std::collections::HashSet; use models::space::spaces; use crate::authority; use crate::errors::SpaceError; use crate::services::service::SpaceService; pub const VIEW_SPACE: &str = "view_space"; pub const READ: &str = "read"; pub const MESSAGE: &str = "message"; pub const MANAGE_MEMBERS: &str = "manage_members"; pub const MANAGE_ROLES: &str = "manage_roles"; pub const MANAGE_INVITES: &str = "manage_invites"; pub const MANAGE_BANS: &str = "manage_bans"; pub const MANAGE_CHANNELS: &str = "manage_channels"; pub const ALL_PERMISSIONS: [&str; 8] = [ VIEW_SPACE, READ, MESSAGE, MANAGE_MEMBERS, MANAGE_ROLES, MANAGE_INVITES, MANAGE_BANS, MANAGE_CHANNELS, ]; #[derive(Debug, Clone, Default)] pub struct Permissions { granted: HashSet, } impl Permissions { pub fn owner() -> Self { Self { granted: ALL_PERMISSIONS.into_iter().map(String::from).collect(), } } pub fn from_vec(values: Vec) -> Self { Self { granted: values.into_iter().collect(), } } pub fn has(&self, action: &str) -> bool { self.granted.contains(action) } pub fn into_vec(self) -> Vec { let mut v: Vec = self.granted.into_iter().collect(); v.sort(); v.dedup(); v } } pub async fn assert_not_banned( state: &SpaceService, space_id: uuid::Uuid, user_id: i64, ) -> Result<(), SpaceError> { if let Ok(Some(member)) = authority::member(state, space_id, user_id).await && member.status() == models::space::MemberStatus::Banned { return Err(SpaceError::Forbidden); } Ok(()) } pub async fn effective_permissions( state: &SpaceService, space: &spaces::Model, user_id: i64, ) -> Result { let granted = crate::services::permission::effective_for( &state.access.database, &state.access.cache, space.id, user_id, ) .await? .into_iter() .filter_map(|permission| permission.strip_prefix("space.").map(str::to_owned)) .collect::>(); if granted.is_empty() { return Err(SpaceError::Forbidden); } Ok(Permissions::from_vec(granted)) } pub async fn require_perm( service: &SpaceService, space: &spaces::Model, caller: i64, action: &str, ) -> Result<(), SpaceError> { let perms = effective_permissions(service, space, caller).await?; if !perms.has(action) { return Err(SpaceError::Forbidden); } Ok(()) }