Skip to main content

alibi_sqlx/store/
organization_roles.rs

1use super::SqlxStore;
2use super::entities::organization_role::Model;
3use crate::model::{self, ActiveRow, SqlxModel};
4use crate::schema::AuthSchema;
5use crate::sql::Sql;
6use alibi_core::error::{AuthError, AuthResult};
7use alibi_core::store::OrganizationRoleStore;
8use alibi_core::types::{
9    CreateOrganizationRole, OrganizationRole, OrganizationRoleSelector, UpdateOrganizationRole,
10};
11use async_trait::async_trait;
12use chrono::Utc;
13use uuid::Uuid;
14
15/// Append the organization scope and role selector.
16fn scope(sql: &mut Sql, organization_id: &str, selector: &OrganizationRoleSelector) {
17    sql.push(" WHERE ");
18    sql.compare(Model::TABLE, "organization_id", " = ", organization_id);
19    sql.push(" AND ");
20    match selector {
21        OrganizationRoleSelector::Id(id) => {
22            sql.compare(Model::TABLE, "id", " = ", id.as_str());
23        }
24        OrganizationRoleSelector::Name(name) => {
25            sql.compare(Model::TABLE, "role", " = ", name.as_str());
26        }
27    }
28}
29
30#[async_trait]
31impl<S: AuthSchema> OrganizationRoleStore for SqlxStore<S> {
32    async fn create_organization_role(
33        &self,
34        data: CreateOrganizationRole,
35    ) -> AuthResult<OrganizationRole> {
36        let mut active = ActiveRow::new();
37        active.set("id", Uuid::new_v4().to_string());
38        active.set("organization_id", data.organization_id);
39        active.set("role", data.role);
40        active.set("permission", serde_json::to_string(&data.permission)?);
41        active.set("created_at", Utc::now());
42        active.set("updated_at", None::<chrono::DateTime<Utc>>);
43        model::insert::<Model>(self.exec(), &active)
44            .await?
45            .try_into()
46    }
47    async fn get_organization_role(
48        &self,
49        organization_id: &str,
50        selector: &OrganizationRoleSelector,
51    ) -> AuthResult<Option<OrganizationRole>> {
52        let mut sql = model::select_model::<Model>(self.exec());
53        scope(&mut sql, organization_id, selector);
54        model::limit_one(&mut sql);
55        self.exec()
56            .fetch_optional::<Model>(sql)
57            .await?
58            .map(TryInto::try_into)
59            .transpose()
60    }
61    async fn list_organization_roles(
62        &self,
63        organization_id: &str,
64    ) -> AuthResult<Vec<OrganizationRole>> {
65        let mut sql = model::select_model::<Model>(self.exec());
66        sql.push(" WHERE ");
67        sql.compare(Model::TABLE, "organization_id", " = ", organization_id);
68        sql.push(" LIMIT ");
69        sql.bind(self.find_many_limit());
70        self.exec()
71            .fetch_all::<Model>(sql)
72            .await?
73            .into_iter()
74            .map(TryInto::try_into)
75            .collect()
76    }
77    async fn count_organization_roles(&self, organization_id: &str) -> AuthResult<usize> {
78        let mut sql = Sql::with(self.exec().engine(), "SELECT COUNT(*) FROM ");
79        sql.ident(Model::TABLE);
80        sql.push(" WHERE ");
81        sql.compare(Model::TABLE, "organization_id", " = ", organization_id);
82        let count = self
83            .exec()
84            .fetch_scalar::<i64>(sql)
85            .await?
86            .unwrap_or_default();
87        usize::try_from(count)
88            .map_err(|_error| AuthError::internal("Organization role count overflow"))
89    }
90    async fn has_organization_role_members(
91        &self,
92        organization_id: &str,
93        role: &str,
94    ) -> AuthResult<bool> {
95        let mut sql = self.organization_models.member.select(self.exec());
96        sql.push(" WHERE ");
97        self.organization_models.member.compare(
98            &mut sql,
99            "organization_id",
100            " = ",
101            organization_id,
102        )?;
103        sql.push(" AND ");
104        self.organization_models
105            .member
106            .compare(&mut sql, "role", " LIKE ", format!("%{role}%"))?;
107        sql.push(" LIMIT ");
108        sql.bind(self.find_many_limit());
109        let members = self
110            .organization_models
111            .member
112            .fetch_all(self.exec(), sql)
113            .await?;
114        Ok(members.iter().any(|member| {
115            member
116                .role
117                .split(',')
118                .map(str::trim)
119                .any(|name| name == role)
120        }))
121    }
122    async fn update_organization_role(
123        &self,
124        organization_id: &str,
125        selector: &OrganizationRoleSelector,
126        update: UpdateOrganizationRole,
127    ) -> AuthResult<OrganizationRole> {
128        let mut select = model::select_model::<Model>(self.exec());
129        scope(&mut select, organization_id, selector);
130        model::limit_one(&mut select);
131        let mut row = self
132            .exec()
133            .fetch_optional::<Model>(select)
134            .await?
135            .ok_or_else(|| AuthError::bad_request("Role not found"))?;
136        let updated_at = Utc::now();
137        let mut sql = Sql::with(self.exec().engine(), "UPDATE ");
138        sql.ident(Model::TABLE);
139        sql.push(" SET ");
140        sql.assign("updated_at", Some(updated_at));
141        if let Some(role) = update.role {
142            sql.push(", ");
143            sql.assign("role", role.clone());
144            row.role = role;
145        }
146        if let Some(permission) = update.permission {
147            let permission = serde_json::to_string(&permission)?;
148            sql.push(", ");
149            sql.assign("permission", permission.clone());
150            row.permission = permission;
151        }
152        scope(&mut sql, organization_id, selector);
153        _ = self.exec().execute(sql).await?;
154        row.updated_at = Some(updated_at);
155        row.try_into()
156    }
157    async fn delete_organization_role(
158        &self,
159        organization_id: &str,
160        selector: &OrganizationRoleSelector,
161    ) -> AuthResult<bool> {
162        let mut sql = Sql::with(self.exec().engine(), "DELETE FROM ");
163        sql.ident(Model::TABLE);
164        scope(&mut sql, organization_id, selector);
165        Ok(self.exec().execute(sql).await? > 0)
166    }
167}