Skip to main content

alibi_core/store/stateless/
roles.rs

1use crate::store::OrganizationRoleStore;
2use crate::store::stateless::StatelessStore;
3use crate::types::{
4    CreateOrganizationRole, OrganizationRole, OrganizationRoleSelector, UpdateOrganizationRole,
5};
6use crate::{AuthError, AuthResult};
7use async_trait::async_trait;
8use chrono::Utc;
9
10fn selected(
11    row: &OrganizationRole,
12    organization_id: &str,
13    selector: &OrganizationRoleSelector,
14) -> bool {
15    row.organization_id == organization_id
16        && match selector {
17            OrganizationRoleSelector::Id(id) => row.id == *id,
18            OrganizationRoleSelector::Name(name) => row.role == *name,
19        }
20}
21#[async_trait]
22impl OrganizationRoleStore for StatelessStore {
23    async fn create_organization_role(
24        &self,
25        data: CreateOrganizationRole,
26    ) -> AuthResult<OrganizationRole> {
27        let row = OrganizationRole {
28            id: uuid::Uuid::new_v4().to_string(),
29            organization_id: data.organization_id,
30            role: data.role,
31            permission: serde_json::to_string(&data.permission)?.into(),
32            created_at: Utc::now(),
33            updated_at: None,
34        };
35        _ = self
36            .organization_state()?
37            .roles
38            .insert(row.id.clone(), row.clone());
39        Ok(row)
40    }
41    async fn get_organization_role(
42        &self,
43        org: &str,
44        selector: &OrganizationRoleSelector,
45    ) -> AuthResult<Option<OrganizationRole>> {
46        Ok(self
47            .organization_state()?
48            .roles
49            .values()
50            .find(|row| selected(row, org, selector))
51            .cloned())
52    }
53    async fn list_organization_roles(&self, org: &str) -> AuthResult<Vec<OrganizationRole>> {
54        Ok(self
55            .organization_state()?
56            .roles
57            .values()
58            .filter(|row| row.organization_id == org)
59            .take(self.find_many_limit)
60            .cloned()
61            .collect())
62    }
63    async fn count_organization_roles(&self, org: &str) -> AuthResult<usize> {
64        Ok(self
65            .organization_state()?
66            .roles
67            .values()
68            .filter(|row| row.organization_id == org)
69            .count())
70    }
71    async fn has_organization_role_members(&self, org: &str, role: &str) -> AuthResult<bool> {
72        Ok(self
73            .organization_state()?
74            .members
75            .values()
76            .filter(|row| row.organization_id == org && row.role.contains(role))
77            .take(self.find_many_limit)
78            .any(|row| row.role.split(',').map(str::trim).any(|part| part == role)))
79    }
80    async fn update_organization_role(
81        &self,
82        org: &str,
83        selector: &OrganizationRoleSelector,
84        update: UpdateOrganizationRole,
85    ) -> AuthResult<OrganizationRole> {
86        let permission = update
87            .permission
88            .map(|p| serde_json::to_string(&p))
89            .transpose()?;
90        let mut state = self.organization_state()?;
91        let mut first = None;
92        let now = Utc::now();
93        // Source update applies the literal patch to every selector match,
94        // returning the first row. Names need not be unique in a memory adapter.
95        for row in state
96            .roles
97            .values_mut()
98            .filter(|row| selected(row, org, selector))
99        {
100            if let Some(role) = &update.role {
101                row.role.clone_from(role);
102            }
103            if let Some(permission) = &permission {
104                row.permission = permission.clone().into();
105            }
106            row.updated_at = Some(now);
107            if first.is_none() {
108                first = Some(row.clone());
109            }
110        }
111        first.ok_or_else(|| AuthError::bad_request("Role not found"))
112    }
113    async fn delete_organization_role(
114        &self,
115        org: &str,
116        selector: &OrganizationRoleSelector,
117    ) -> AuthResult<bool> {
118        let mut state = self.organization_state()?;
119        let before = state.roles.len();
120        state.roles.retain(|_, row| !selected(row, org, selector));
121        Ok(before != state.roles.len())
122    }
123}