feat(spaces): add space roles service for permission cascading
Create rooms::roles::Service with in-memory caches for role definitions, user-role assignments, room requirements, and room-to-space mappings. Register the service in the service stack alongside other room services. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c5ffc4963c
commit
053bdf00da
3 changed files with 91 additions and 0 deletions
|
|
@ -7,6 +7,7 @@ pub mod metadata;
|
|||
pub mod outlier;
|
||||
pub mod pdu_metadata;
|
||||
pub mod read_receipt;
|
||||
pub mod roles;
|
||||
pub mod search;
|
||||
pub mod short;
|
||||
pub mod spaces;
|
||||
|
|
@ -31,6 +32,7 @@ pub struct Service {
|
|||
pub outlier: Arc<outlier::Service>,
|
||||
pub pdu_metadata: Arc<pdu_metadata::Service>,
|
||||
pub read_receipt: Arc<read_receipt::Service>,
|
||||
pub roles: Arc<roles::Service>,
|
||||
pub search: Arc<search::Service>,
|
||||
pub short: Arc<short::Service>,
|
||||
pub spaces: Arc<spaces::Service>,
|
||||
|
|
|
|||
88
src/service/rooms/roles/mod.rs
Normal file
88
src/service/rooms/roles/mod.rs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
fmt::Write,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use conduwuit::Result;
|
||||
use ruma::{OwnedRoomId, OwnedUserId};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::{Dep, rooms};
|
||||
|
||||
/// Definition of a role within a space, including its permissions.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoleDefinition {
|
||||
/// Human-readable name of the role.
|
||||
pub name: String,
|
||||
/// Set of permission strings granted by this role.
|
||||
pub permissions: HashSet<String>,
|
||||
/// Priority for ordering/conflict resolution (higher = more priority).
|
||||
pub priority: i64,
|
||||
}
|
||||
|
||||
pub struct Service {
|
||||
#[allow(dead_code)]
|
||||
services: Services,
|
||||
/// Space ID -> role name -> role definition
|
||||
pub roles: RwLock<HashMap<OwnedRoomId, BTreeMap<String, RoleDefinition>>>,
|
||||
/// Space ID -> user ID -> assigned role names
|
||||
pub user_roles: RwLock<HashMap<OwnedRoomId, HashMap<OwnedUserId, HashSet<String>>>>,
|
||||
/// Space ID -> child room ID -> required role names
|
||||
pub room_requirements: RwLock<HashMap<OwnedRoomId, HashMap<OwnedRoomId, HashSet<String>>>>,
|
||||
/// Child room ID -> parent space ID
|
||||
pub room_to_space: RwLock<HashMap<OwnedRoomId, OwnedRoomId>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Services {
|
||||
state_accessor: Dep<rooms::state_accessor::Service>,
|
||||
state_cache: Dep<rooms::state_cache::Service>,
|
||||
state: Dep<rooms::state::Service>,
|
||||
spaces: Dep<rooms::spaces::Service>,
|
||||
timeline: Dep<rooms::timeline::Service>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
services: Services {
|
||||
state_accessor: args
|
||||
.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
|
||||
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
|
||||
state: args.depend::<rooms::state::Service>("rooms::state"),
|
||||
spaces: args.depend::<rooms::spaces::Service>("rooms::spaces"),
|
||||
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
|
||||
},
|
||||
roles: RwLock::new(HashMap::new()),
|
||||
user_roles: RwLock::new(HashMap::new()),
|
||||
room_requirements: RwLock::new(HashMap::new()),
|
||||
room_to_space: RwLock::new(HashMap::new()),
|
||||
}))
|
||||
}
|
||||
|
||||
async fn memory_usage(&self, out: &mut (dyn Write + Send)) -> Result {
|
||||
let roles = self.roles.read().await.len();
|
||||
let user_roles = self.user_roles.read().await.len();
|
||||
let room_requirements = self.room_requirements.read().await.len();
|
||||
let room_to_space = self.room_to_space.read().await.len();
|
||||
|
||||
writeln!(out, "roles: {roles}")?;
|
||||
writeln!(out, "user_roles: {user_roles}")?;
|
||||
writeln!(out, "room_requirements: {room_requirements}")?;
|
||||
writeln!(out, "room_to_space: {room_to_space}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_cache(&self) {
|
||||
self.roles.write().await.clear();
|
||||
self.user_roles.write().await.clear();
|
||||
self.room_requirements.write().await.clear();
|
||||
self.room_to_space.write().await.clear();
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
|
@ -94,6 +94,7 @@ impl Services {
|
|||
outlier: build!(rooms::outlier::Service),
|
||||
pdu_metadata: build!(rooms::pdu_metadata::Service),
|
||||
read_receipt: build!(rooms::read_receipt::Service),
|
||||
roles: build!(rooms::roles::Service),
|
||||
search: build!(rooms::search::Service),
|
||||
short: build!(rooms::short::Service),
|
||||
spaces: build!(rooms::spaces::Service),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue