Skip to main content

oxidite_auth/
rbac.rs

1use oxidite_db::sqlx;
2use oxidite_db::sqlx::FromRow;
3
4#[derive(FromRow, Clone, Debug)]
5pub struct Role {
6    pub id: i64,
7    pub name: String,
8    pub description: Option<String>,
9    pub created_at: i64,
10    pub updated_at: i64,
11}
12
13#[derive(FromRow, Clone, Debug)]
14pub struct Permission {
15    pub id: i64,
16    pub name: String,
17    pub resource: String,
18    pub action: String,
19    pub description: Option<String>,
20    pub created_at: i64,
21    pub updated_at: i64,
22}
23
24impl Role {
25    /// Get all permissions for this role
26    pub async fn permissions(&self, db: &impl oxidite_db::Database) -> oxidite_db::Result<Vec<Permission>> {
27        let query = oxidite_db::sqlx::query(
28            "SELECT p.* FROM permissions p
29             INNER JOIN role_permissions rp ON p.id = rp.permission_id
30             WHERE rp.role_id = ?"
31        )
32            .bind(self.id);
33
34        let rows = db.fetch_all(query).await?;
35        let mut permissions = Vec::new();
36        
37        for row in rows {
38            permissions.push(sqlx::FromRow::from_row(&row)?);
39        }
40        
41        Ok(permissions)
42    }
43    
44    /// Check if role has a specific permission
45    pub async fn has_permission(&self, db: &impl oxidite_db::Database, permission_name: &str) -> oxidite_db::Result<bool> {
46        let query = oxidite_db::sqlx::query(
47            "SELECT 1 FROM permissions p
48             INNER JOIN role_permissions rp ON p.id = rp.permission_id
49             WHERE rp.role_id = ? AND p.name = ?
50             LIMIT 1"
51        )
52            .bind(self.id)
53            .bind(permission_name);
54        Ok(db.fetch_one(query).await?.is_some())
55    }
56}
57
58impl Permission {
59    /// Check if permission matches resource and action
60    pub fn matches(&self, resource: &str, action: &str) -> bool {
61        self.resource == resource && self.action == action
62    }
63}