dmsc/auth/permissions.rs
1//! Copyright © 2025 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//! http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! Role-based access control (RBAC) implementation for DMSC.
19//!
20//! This module provides a comprehensive RBAC system for managing permissions,
21//! roles, and user role assignments. It supports:
22//! - Fine-grained permission definitions
23//! - Role management with inheritance support
24//! - User role assignments
25//! - Permission checking for users
26//! - System roles that cannot be deleted
27//! - Wildcard permissions for administrative access
28//!
29//! # Design Principles
30//! - **Separation of Concerns**: Permissions, roles, and user assignments are managed separately
31//! - **Thread Safety**: Uses RwLock for concurrent access to data structures
32//! - **Flexibility**: Supports both explicit and wildcard permissions
33//! - **Security**: System roles are protected from deletion
34//! - **Performance**: Efficient permission checking with hash sets
35//!
36//! # Usage Examples
37//! ```rust
38//! // Create a permission manager
39//! let permission_manager = DMSCPermissionManager::new();
40//!
41//! // Create a permission
42//! let read_device_perm = DMSCPermission {
43//! id: "read:device".to_string(),
44//! name: "Read Device".to_string(),
45//! description: "Allows reading device information".to_string(),
46//! resource: "device".to_string(),
47//! action: "read".to_string(),
48//! };
49//! permission_manager.create_permission(read_device_perm).await?;
50//!
51//! // Create a role
52//! let device_admin_role = DMSCRole::new(
53//! "device_admin".to_string(),
54//! "Device Administrator".to_string(),
55//! "Manages devices".to_string(),
56//! vec!["read:device", "write:device"].iter().map(|s| s.to_string()).collect()
57//! );
58//! permission_manager.create_role(device_admin_role).await?;
59//!
60//! // Assign role to user
61//! permission_manager.assign_role_to_user("user123".to_string(), "device_admin".to_string()).await?;
62//!
63//! // Check if user has permission
64//! let has_perm = permission_manager.has_permission("user123", "read:device").await?;
65//! ```
66
67#![allow(non_snake_case)]
68
69use serde::{Deserialize, Serialize};
70use std::collections::{HashMap, HashSet};
71use tokio::sync::RwLock;
72
73#[cfg(feature = "pyo3")]
74use pyo3::PyResult;
75
76/// Permission definition for fine-grained access control.
77///
78/// This struct defines a permission with a unique ID, name, description,
79/// resource, and action. Permissions follow the "resource:action" convention.
80#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct DMSCPermission {
83 /// Unique permission identifier following "resource:action" format (e.g., "read:device")
84 pub id: String,
85 /// Human-readable name for the permission
86 pub name: String,
87 /// Detailed description explaining what this permission allows
88 pub description: String,
89 /// Resource being accessed (e.g., "device", "user", "data")
90 pub resource: String,
91 /// Action being performed (e.g., "read", "write", "delete")
92 pub action: String,
93}
94
95#[cfg(feature = "pyo3")]
96#[pyo3::prelude::pymethods]
97impl DMSCPermission {
98 #[new]
99 fn py_new(
100 id: Option<String>,
101 name: String,
102 description: String,
103 resource: String,
104 action: String,
105 ) -> Self {
106 Self {
107 id: id.unwrap_or_else(|| format!("{}:{}", resource, action)),
108 name,
109 description,
110 resource,
111 action,
112 }
113 }
114}
115
116/// Role definition for grouping permissions.
117///
118/// Roles are collections of permissions that can be assigned to users.
119/// System roles cannot be deleted and are created automatically during initialization.
120#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct DMSCRole {
123 /// Unique role identifier
124 pub id: String,
125 /// Human-readable name for the role
126 pub name: String,
127 /// Detailed description explaining the role's purpose and access level
128 pub description: String,
129 /// Set of permission IDs assigned to this role
130 pub permissions: HashSet<String>,
131 /// Whether this is a system role that cannot be deleted
132 pub is_system: bool,
133}
134
135#[cfg(feature = "pyo3")]
136#[pyo3::prelude::pymethods]
137impl DMSCRole {
138 #[new]
139 fn py_new(
140 id: Option<String>,
141 name: String,
142 description: String,
143 permissions: Vec<String>,
144 is_system: bool,
145 ) -> Self {
146 Self {
147 id: id.unwrap_or_else(|| name.to_lowercase().replace(' ', "_")),
148 name,
149 description,
150 permissions: permissions.into_iter().collect(),
151 is_system,
152 }
153 }
154}
155
156impl DMSCRole {
157 /// Creates a new role with the specified permissions.
158 ///
159 /// # Parameters
160 /// - `id`: Unique role identifier
161 /// - `name`: Human-readable name
162 /// - `description`: Detailed description
163 /// - `permissions`: Set of permission IDs
164 ///
165 /// # Returns
166 /// A new instance of `DMSCRole`
167 pub fn new(id: String, name: String, description: String, permissions: HashSet<String>) -> Self {
168 Self {
169 id,
170 name,
171 description,
172 permissions,
173 is_system: false,
174 }
175 }
176
177 /// Checks if the role has the specified permission.
178 ///
179 /// # Parameters
180 /// - `permission_id`: Permission ID to check
181 ///
182 /// # Returns
183 /// `true` if the role has the permission, otherwise `false`
184 #[inline]
185 pub fn has_permission(&self, permission_id: &str) -> bool {
186 self.permissions.contains(permission_id)
187 }
188
189 /// Adds a permission to the role.
190 ///
191 /// # Parameters
192 /// - `permission_id`: Permission ID to add
193 #[inline]
194 pub fn add_permission(&mut self, permission_id: String) {
195 self.permissions.insert(permission_id);
196 }
197
198 /// Removes a permission from the role.
199 ///
200 /// # Parameters
201 /// - `permission_id`: Permission ID to remove
202 #[inline]
203 pub fn remove_permission(&mut self, permission_id: &str) {
204 self.permissions.remove(permission_id);
205 }
206}
207
208/// Permission manager for handling permissions, roles, and user assignments.
209///
210/// This struct manages the entire RBAC system, including:
211/// - Permission CRUD operations
212/// - Role CRUD operations
213/// - User role assignments
214/// - Permission checking for users
215#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
216pub struct DMSCPermissionManager {
217 /// Hash map of permissions indexed by permission ID
218 permissions: RwLock<HashMap<String, DMSCPermission>>,
219 /// Hash map of roles indexed by role ID
220 roles: RwLock<HashMap<String, DMSCRole>>,
221 /// Hash map of user role assignments indexed by user ID
222 user_roles: RwLock<HashMap<String, HashSet<String>>>,
223}
224
225impl Default for DMSCPermissionManager {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231impl DMSCPermissionManager {
232 /// Creates a new permission manager with default system roles.
233 ///
234 /// Initializes the manager with two default system roles:
235 /// - `admin`: Has wildcard permission ("*") for all access
236 /// - `user`: Has basic user permissions
237 ///
238 /// **Performance Note**: This method uses `blocking_write` during initialization
239 /// to set up default roles. For production use, consider using `new_async()` or
240 /// lazy initialization patterns to avoid blocking the async runtime.
241 ///
242 /// # Returns
243 /// A new instance of `DMSCPermissionManager`
244 pub fn new() -> Self {
245 let mut manager = Self {
246 permissions: RwLock::new(HashMap::new()),
247 roles: RwLock::new(HashMap::new()),
248 user_roles: RwLock::new(HashMap::new()),
249 };
250
251 // Initialize with default system roles
252 // Note: This uses blocking_write which may block the async runtime
253 manager.initialize_default_roles();
254 manager
255 }
256
257 /// Creates a new permission manager asynchronously with default system roles.
258 ///
259 /// This is the preferred method for creating a permission manager in async contexts
260 /// as it avoids blocking the runtime during initialization.
261 ///
262 /// Initializes the manager with two default system roles:
263 /// - `admin`: Has wildcard permission ("*") for all access
264 /// - `user`: Has basic user permissions
265 ///
266 /// # Returns
267 /// A new instance of `DMSCPermissionManager`
268 pub async fn new_async() -> Self {
269 let manager = Self {
270 permissions: RwLock::new(HashMap::new()),
271 roles: RwLock::new(HashMap::new()),
272 user_roles: RwLock::new(HashMap::new()),
273 };
274
275 // Initialize with default system roles asynchronously
276 manager.initialize_default_roles_async().await;
277 manager
278 }
279
280 /// Initializes default system roles.
281 ///
282 /// This method is called during construction to create the default admin
283 /// and user roles. It uses `blocking_write` because it's called from a
284 /// non-async context.
285 ///
286 /// **Performance Note**: This method is called during initialization and uses
287 /// `blocking_write` to avoid async complexity in the constructor. In production
288 /// scenarios, consider using an async factory pattern or lazy initialization.
289 fn initialize_default_roles(&mut self) {
290 // This would be called in blocking context, so we use blocking_write
291 // Note: In production, consider using an async factory pattern to avoid blocking
292 let mut roles = self.roles.blocking_write();
293
294 // Admin role - all permissions
295 let admin_permissions: HashSet<String> = vec![
296 "*".to_string(), // Wildcard permission
297 ].into_iter().collect();
298
299 let admin_role = DMSCRole {
300 id: "admin".to_string(),
301 name: "Administrator".to_string(),
302 description: "Full system access".to_string(),
303 permissions: admin_permissions,
304 is_system: true,
305 };
306
307 roles.insert("admin".to_string(), admin_role);
308
309 // User role - basic permissions
310 let user_permissions: HashSet<String> = vec![
311 "read:profile".to_string(),
312 "update:profile".to_string(),
313 "read:own_data".to_string(),
314 ].into_iter().collect();
315
316 let user_role = DMSCRole {
317 id: "user".to_string(),
318 name: "User".to_string(),
319 description: "Standard user access".to_string(),
320 permissions: user_permissions,
321 is_system: true,
322 };
323
324 roles.insert("user".to_string(), user_role);
325 }
326
327 /// Initializes default system roles asynchronously.
328 ///
329 /// This method is the async version of `initialize_default_roles` that avoids
330 /// using `blocking_write`. It should be used when creating the permission manager
331 /// in async contexts.
332 ///
333 /// **Performance**: This method uses async write locks and is preferred for
334 /// async initialization scenarios.
335 async fn initialize_default_roles_async(&self) {
336 let mut roles = self.roles.write().await;
337
338 // Admin role - all permissions
339 let admin_permissions: HashSet<String> = vec![
340 "*".to_string(), // Wildcard permission
341 ].into_iter().collect();
342
343 let admin_role = DMSCRole {
344 id: "admin".to_string(),
345 name: "Administrator".to_string(),
346 description: "Full system access".to_string(),
347 permissions: admin_permissions,
348 is_system: true,
349 };
350
351 roles.insert("admin".to_string(), admin_role);
352
353 // User role - basic permissions
354 let user_permissions: HashSet<String> = vec![
355 "read:profile".to_string(),
356 "update:profile".to_string(),
357 "read:own_data".to_string(),
358 ].into_iter().collect();
359
360 let user_role = DMSCRole {
361 id: "user".to_string(),
362 name: "User".to_string(),
363 description: "Standard user access".to_string(),
364 permissions: user_permissions,
365 is_system: true,
366 };
367
368 roles.insert("user".to_string(), user_role);
369 }
370
371 /// Creates a new permission.
372 ///
373 /// # Parameters
374 /// - `permission`: Permission to create
375 ///
376 /// # Returns
377 /// `Ok(())` if the permission was successfully created
378 pub async fn create_permission(&self, permission: DMSCPermission) -> crate::core::DMSCResult<()> {
379 let mut permissions = self.permissions.write().await;
380 permissions.insert(permission.id.clone(), permission);
381 Ok(())
382 }
383
384 /// Gets a permission by ID.
385 ///
386 /// # Parameters
387 /// - `permission_id`: Permission ID to retrieve
388 ///
389 /// # Returns
390 /// `Some(DMSCPermission)` if the permission exists, otherwise `None`
391 pub async fn get_permission(&self, permission_id: &str) -> crate::core::DMSCResult<Option<DMSCPermission>> {
392 let permissions = self.permissions.read().await;
393 Ok(permissions.get(permission_id).cloned())
394 }
395
396 /// Creates a new role.
397 ///
398 /// # Parameters
399 /// - `role`: Role to create
400 ///
401 /// # Returns
402 /// `Ok(())` if the role was successfully created
403 pub async fn create_role(&self, role: DMSCRole) -> crate::core::DMSCResult<()> {
404 let mut roles = self.roles.write().await;
405 roles.insert(role.id.clone(), role);
406 Ok(())
407 }
408
409 /// Gets a role by ID.
410 ///
411 /// # Parameters
412 /// - `role_id`: Role ID to retrieve
413 ///
414 /// # Returns
415 /// `Some(DMSCRole)` if the role exists, otherwise `None`
416 pub async fn get_role(&self, role_id: &str) -> crate::core::DMSCResult<Option<DMSCRole>> {
417 let roles = self.roles.read().await;
418 Ok(roles.get(role_id).cloned())
419 }
420
421 /// Assigns a role to a user.
422 ///
423 /// # Parameters
424 /// - `user_id`: User ID to assign the role to
425 /// - `role_id`: Role ID to assign
426 ///
427 /// # Returns
428 /// `true` if the role was successfully assigned, `false` if the role doesn't exist
429 pub async fn assign_role_to_user(&self, user_id: String, role_id: String) -> crate::core::DMSCResult<bool> {
430 // Check if role exists
431 let roles = self.roles.read().await;
432 if !roles.contains_key(&role_id) {
433 return Ok(false);
434 }
435 drop(roles);
436
437 let mut user_roles = self.user_roles.write().await;
438 let user_role_set = user_roles.entry(user_id).or_insert_with(HashSet::new);
439 let was_added = user_role_set.insert(role_id);
440 Ok(was_added)
441 }
442
443 /// Removes a role from a user.
444 ///
445 /// # Parameters
446 /// - `user_id`: User ID to remove the role from
447 /// - `role_id`: Role ID to remove
448 ///
449 /// # Returns
450 /// `true` if the role was successfully removed, `false` if the user didn't have the role
451 pub async fn remove_role_from_user(&self, user_id: &str, role_id: &str) -> crate::core::DMSCResult<bool> {
452 let mut user_roles = self.user_roles.write().await;
453
454 if let Some(user_role_set) = user_roles.get_mut(user_id) {
455 let was_removed = user_role_set.remove(role_id);
456 if user_role_set.is_empty() {
457 user_roles.remove(user_id);
458 }
459 Ok(was_removed)
460 } else {
461 Ok(false)
462 }
463 }
464
465 /// Gets all roles assigned to a user.
466 ///
467 /// # Parameters
468 /// - `user_id`: User ID to retrieve roles for
469 ///
470 /// # Returns
471 /// A vector of `DMSCRole` objects assigned to the user
472 pub async fn get_user_roles(&self, user_id: &str) -> crate::core::DMSCResult<Vec<DMSCRole>> {
473 let user_roles = self.user_roles.read().await;
474 let roles = self.roles.read().await;
475
476 let mut result = if let Some(user_role_ids) = user_roles.get(user_id) {
477 Vec::with_capacity(user_role_ids.len())
478 } else {
479 Vec::new()
480 };
481
482 if let Some(user_role_ids) = user_roles.get(user_id) {
483 for role_id in user_role_ids {
484 if let Some(role) = roles.get(role_id) {
485 result.push(role.clone());
486 }
487 }
488 }
489
490 Ok(result)
491 }
492
493 /// Checks if a user has a specific permission.
494 ///
495 /// # Parameters
496 /// - `user_id`: User ID to check
497 /// - `permission_id`: Permission ID to check for
498 ///
499 /// # Returns
500 /// `true` if the user has the permission, otherwise `false`
501 ///
502 /// # Notes
503 /// - Users with the wildcard permission ("*") have all permissions
504 /// - Permission checking is done by examining all roles assigned to the user
505 pub async fn has_permission(&self, user_id: &str, permission_id: &str) -> crate::core::DMSCResult<bool> {
506 let user_roles = self.user_roles.read().await;
507 let roles = self.roles.read().await;
508
509 if let Some(user_role_ids) = user_roles.get(user_id) {
510 for role_id in user_role_ids {
511 if let Some(role) = roles.get(role_id) {
512 // Check for wildcard permission
513 if role.permissions.contains("*") {
514 return Ok(true);
515 }
516
517 if role.permissions.contains(permission_id) {
518 return Ok(true);
519 }
520 }
521 }
522 }
523
524 Ok(false)
525 }
526
527 /// Checks if a user has any of the specified permissions.
528 ///
529 /// # Parameters
530 /// - `user_id`: User ID to check
531 /// - `permissions`: List of permission IDs to check for
532 ///
533 /// # Returns
534 /// `true` if the user has at least one of the permissions, otherwise `false`
535 pub async fn has_any_permission(&self, user_id: &str, permissions: &[String]) -> crate::core::DMSCResult<bool> {
536 for permission in permissions {
537 if self.has_permission(user_id, permission).await? {
538 return Ok(true);
539 }
540 }
541 Ok(false)
542 }
543
544 /// Checks if a user has all of the specified permissions.
545 ///
546 /// # Parameters
547 /// - `user_id`: User ID to check
548 /// - `permissions`: List of permission IDs to check for
549 ///
550 /// # Returns
551 /// `true` if the user has all of the permissions, otherwise `false`
552 pub async fn has_all_permissions(&self, user_id: &str, permissions: &[String]) -> crate::core::DMSCResult<bool> {
553 for permission in permissions {
554 if !self.has_permission(user_id, permission).await? {
555 return Ok(false);
556 }
557 }
558 Ok(true)
559 }
560
561 /// Gets all permissions assigned to a user.
562 ///
563 /// # Parameters
564 /// - `user_id`: User ID to retrieve permissions for
565 ///
566 /// # Returns
567 /// A set of permission IDs assigned to the user
568 pub async fn get_user_permissions(&self, user_id: &str) -> crate::core::DMSCResult<HashSet<String>> {
569 let user_roles = self.user_roles.read().await;
570 let roles = self.roles.read().await;
571
572 let mut permissions = HashSet::new();
573
574 if let Some(user_role_ids) = user_roles.get(user_id) {
575 for role_id in user_role_ids {
576 if let Some(role) = roles.get(role_id) {
577 permissions.extend(role.permissions.clone());
578 }
579 }
580 }
581
582 Ok(permissions)
583 }
584
585 /// Deletes a permission.
586 ///
587 /// # Parameters
588 /// - `permission_id`: Permission ID to delete
589 ///
590 /// # Returns
591 /// `true` if the permission was successfully deleted, otherwise `false`
592 pub async fn delete_permission(&self, permission_id: &str) -> crate::core::DMSCResult<bool> {
593 let mut permissions = self.permissions.write().await;
594 Ok(permissions.remove(permission_id).is_some())
595 }
596
597 /// Deletes a role.
598 ///
599 /// # Parameters
600 /// - `role_id`: Role ID to delete
601 ///
602 /// # Returns
603 /// `true` if the role was successfully deleted, otherwise `false`
604 ///
605 /// # Notes
606 /// - System roles cannot be deleted
607 /// - If the role is deleted, it is removed from all users
608 pub async fn delete_role(&self, role_id: &str) -> crate::core::DMSCResult<bool> {
609 // Don't delete system roles
610 let roles = self.roles.read().await;
611 if let Some(role) = roles.get(role_id) {
612 if role.is_system {
613 return Ok(false);
614 }
615 }
616 drop(roles);
617
618 let mut roles = self.roles.write().await;
619 let was_deleted = roles.remove(role_id).is_some();
620
621 if was_deleted {
622 // Remove role from all users
623 let mut user_roles = self.user_roles.write().await;
624 for user_role_set in user_roles.values_mut() {
625 user_role_set.remove(role_id);
626 }
627 }
628
629 Ok(was_deleted)
630 }
631
632 /// Lists all permissions.
633 ///
634 /// # Returns
635 /// A vector of all registered permissions
636 pub async fn list_permissions(&self) -> crate::core::DMSCResult<Vec<DMSCPermission>> {
637 let permissions = self.permissions.read().await;
638 Ok(permissions.values().cloned().collect())
639 }
640
641 /// Lists all roles.
642 ///
643 /// # Returns
644 /// A vector of all registered roles
645 pub async fn list_roles(&self) -> crate::core::DMSCResult<Vec<DMSCRole>> {
646 let roles = self.roles.read().await;
647 Ok(roles.values().cloned().collect())
648 }
649}
650
651#[cfg(feature = "pyo3")]
652/// Python bindings for the Permission Manager.
653///
654/// This module provides Python interface to DMSC RBAC functionality,
655/// enabling Python applications to manage permissions, roles, and user assignments.
656///
657/// ## Supported Operations
658///
659/// - Permission creation and management
660/// - Role creation and management with permission assignments
661/// - User role assignments and removal
662/// - Permission checking for users
663/// - Permission and role listing
664///
665/// ## Python Usage Example
666///
667/// ```python
668/// from dmsc import DMSCPermission, DMSCRole, DMSCPermissionManager
669///
670/// # Create permission manager
671/// perm_manager = DMSCPermissionManager()
672///
673/// # Create a permission
674/// permission = DMSCPermission(
675/// id="read:device",
676/// name="Read Device",
677/// description="Allows reading device information",
678/// resource="device",
679/// action="read",
680/// )
681///
682/// # Create a role
683/// role = DMSCRole(
684/// id="device_admin",
685/// name="Device Administrator",
686/// description="Manages devices",
687/// permissions=["read:device", "write:device"],
688/// is_system=False,
689/// )
690/// # Note: Async operations require Python 3.7+ with asyncio
691/// ```
692#[pyo3::prelude::pymethods]
693impl DMSCPermissionManager {
694 #[new]
695 fn py_new() -> PyResult<Self> {
696 Ok(Self::new())
697 }
698
699 #[pyo3(name = "create_permission")]
700 fn create_permission_impl(&self, permission: DMSCPermission) -> PyResult<()> {
701 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
702 rt.block_on(async {
703 self.create_permission(permission).await
704 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
705 })
706 }
707
708 #[pyo3(name = "create_role")]
709 fn create_role_impl(&self, role: DMSCRole) -> PyResult<()> {
710 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
711 rt.block_on(async {
712 self.create_role(role).await
713 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
714 })
715 }
716
717 #[pyo3(name = "assign_role_to_user")]
718 fn assign_role_to_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
719 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
720 rt.block_on(async {
721 self.assign_role_to_user(user_id, role_id).await
722 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
723 })
724 }
725
726 #[pyo3(name = "has_permission")]
727 fn has_permission_impl(&self, user_id: String, permission_id: String) -> PyResult<bool> {
728 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
729 rt.block_on(async {
730 self.has_permission(&user_id, &permission_id).await
731 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
732 })
733 }
734
735 #[pyo3(name = "get_user_roles")]
736 fn get_user_roles_impl(&self, user_id: String) -> PyResult<Vec<DMSCRole>> {
737 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
738 rt.block_on(async {
739 self.get_user_roles(&user_id).await
740 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
741 })
742 }
743
744 #[pyo3(name = "get_user_permissions")]
745 fn get_user_permissions_impl(&self, user_id: String) -> PyResult<Vec<String>> {
746 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
747 rt.block_on(async {
748 self.get_user_permissions(&user_id).await
749 .map(|perms| perms.into_iter().collect())
750 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
751 })
752 }
753
754 #[pyo3(name = "remove_role_from_user")]
755 fn remove_role_from_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
756 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
757 rt.block_on(async {
758 self.remove_role_from_user(&user_id, &role_id).await
759 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
760 })
761 }
762
763 #[pyo3(name = "list_roles")]
764 fn list_roles_impl(&self) -> PyResult<Vec<DMSCRole>> {
765 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
766 rt.block_on(async {
767 self.list_roles().await
768 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
769 })
770 }
771
772 #[pyo3(name = "list_permissions")]
773 fn list_permissions_impl(&self) -> PyResult<Vec<DMSCPermission>> {
774 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
775 rt.block_on(async {
776 self.list_permissions().await
777 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
778 })
779 }
780
781 #[pyo3(name = "delete_role")]
782 fn delete_role_impl(&self, role_id: String) -> PyResult<bool> {
783 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
784 rt.block_on(async {
785 self.delete_role(&role_id).await
786 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
787 })
788 }
789
790 #[pyo3(name = "delete_permission")]
791 fn delete_permission_impl(&self, permission_id: String) -> PyResult<bool> {
792 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
793 rt.block_on(async {
794 self.delete_permission(&permission_id).await
795 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
796 })
797 }
798
799 #[pyo3(name = "get_role")]
800 fn get_role_impl(&self, role_id: String) -> PyResult<Option<DMSCRole>> {
801 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
802 rt.block_on(async {
803 self.get_role(&role_id).await
804 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
805 })
806 }
807
808 #[pyo3(name = "get_permission")]
809 fn get_permission_impl(&self, permission_id: String) -> PyResult<Option<DMSCPermission>> {
810 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
811 rt.block_on(async {
812 self.get_permission(&permission_id).await
813 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
814 })
815 }
816
817 #[pyo3(name = "has_any_permission")]
818 fn has_any_permission_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
819 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
820 rt.block_on(async {
821 self.has_any_permission(&user_id, &permissions).await
822 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
823 })
824 }
825
826 #[pyo3(name = "has_all_permissions")]
827 fn has_all_permissions_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
828 let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
829 rt.block_on(async {
830 self.has_all_permissions(&user_id, &permissions).await
831 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
832 })
833 }
834}