use super::SqlxStore;
use super::entities::organization_role::Model;
use crate::model::{self, ActiveRow, SqlxModel};
use crate::schema::AuthSchema;
use crate::sql::Sql;
use alibi_core::error::{AuthError, AuthResult};
use alibi_core::store::OrganizationRoleStore;
use alibi_core::types::{
CreateOrganizationRole, OrganizationRole, OrganizationRoleSelector, UpdateOrganizationRole,
};
use async_trait::async_trait;
use chrono::Utc;
use uuid::Uuid;
fn scope(sql: &mut Sql, organization_id: &str, selector: &OrganizationRoleSelector) {
sql.push(" WHERE ");
sql.compare(Model::TABLE, "organizationId", " = ", organization_id);
sql.push(" AND ");
match selector {
OrganizationRoleSelector::Id(id) => {
sql.compare(Model::TABLE, "id", " = ", id.as_str());
}
OrganizationRoleSelector::Name(name) => {
sql.compare(Model::TABLE, "role", " = ", name.as_str());
}
}
}
#[async_trait]
impl<S: AuthSchema> OrganizationRoleStore for SqlxStore<S> {
async fn create_organization_role(
&self,
data: CreateOrganizationRole,
) -> AuthResult<OrganizationRole> {
let mut active = ActiveRow::new();
active.set(
"id",
self.generated_id(self.exec(), "organizationRole", "organizationRole", "id")
.await?
.unwrap_or_else(|| Uuid::new_v4().to_string()),
);
active.set("organizationId", data.organization_id);
active.set("role", data.role);
active.set("permission", serde_json::to_string(&data.permission)?);
active.set("createdAt", Utc::now());
active.set("updatedAt", None::<chrono::DateTime<Utc>>);
model::insert::<Model>(self.exec(), &active)
.await?
.try_into()
}
async fn get_organization_role(
&self,
organization_id: &str,
selector: &OrganizationRoleSelector,
) -> AuthResult<Option<OrganizationRole>> {
let mut sql = model::select_model::<Model>(self.exec());
scope(&mut sql, organization_id, selector);
model::limit_one(&mut sql);
self.exec()
.fetch_optional::<Model>(sql)
.await?
.map(TryInto::try_into)
.transpose()
}
async fn list_organization_roles(
&self,
organization_id: &str,
) -> AuthResult<Vec<OrganizationRole>> {
let mut sql = model::select_model::<Model>(self.exec());
sql.push(" WHERE ");
sql.compare(Model::TABLE, "organizationId", " = ", organization_id);
sql.push(" LIMIT ");
sql.bind(self.find_many_limit());
self.exec()
.fetch_all::<Model>(sql)
.await?
.into_iter()
.map(TryInto::try_into)
.collect()
}
async fn count_organization_roles(&self, organization_id: &str) -> AuthResult<usize> {
let mut sql = Sql::with(self.exec().engine(), "SELECT COUNT(*) FROM ");
sql.ident(Model::TABLE);
sql.push(" WHERE ");
sql.compare(Model::TABLE, "organizationId", " = ", organization_id);
let count = self
.exec()
.fetch_scalar::<i64>(sql)
.await?
.unwrap_or_default();
usize::try_from(count)
.map_err(|_error| AuthError::internal("Organization role count overflow"))
}
async fn has_organization_role_members(
&self,
organization_id: &str,
role: &str,
) -> AuthResult<bool> {
let mut sql = self.organization_models.member.select(self.exec());
sql.push(" WHERE ");
self.organization_models.member.compare(
&mut sql,
"organizationId",
" = ",
organization_id,
)?;
sql.push(" AND ");
self.organization_models
.member
.compare(&mut sql, "role", " LIKE ", format!("%{role}%"))?;
sql.push(" LIMIT ");
sql.bind(self.find_many_limit());
let members = self
.organization_models
.member
.fetch_all(self.exec(), sql)
.await?;
Ok(members.iter().any(|member| {
member
.role
.split(',')
.map(str::trim)
.any(|name| name == role)
}))
}
async fn update_organization_role(
&self,
organization_id: &str,
selector: &OrganizationRoleSelector,
update: UpdateOrganizationRole,
) -> AuthResult<OrganizationRole> {
let mut select = model::select_model::<Model>(self.exec());
scope(&mut select, organization_id, selector);
model::limit_one(&mut select);
let mut row = self
.exec()
.fetch_optional::<Model>(select)
.await?
.ok_or_else(|| AuthError::bad_request("Role not found"))?;
let updated_at = Utc::now();
let mut sql = Sql::with(self.exec().engine(), "UPDATE ");
sql.ident(Model::TABLE);
sql.push(" SET ");
sql.assign("updatedAt", Some(updated_at));
if let Some(role) = update.role {
sql.push(", ");
sql.assign("role", role.clone());
row.role = role;
}
if let Some(permission) = update.permission {
let permission = serde_json::to_string(&permission)?;
sql.push(", ");
sql.assign("permission", permission.clone());
row.permission = permission;
}
scope(&mut sql, organization_id, selector);
_ = self.exec().execute(sql).await?;
row.updated_at = Some(updated_at);
row.try_into()
}
async fn delete_organization_role(
&self,
organization_id: &str,
selector: &OrganizationRoleSelector,
) -> AuthResult<bool> {
let mut sql = Sql::with(self.exec().engine(), "DELETE FROM ");
sql.ident(Model::TABLE);
scope(&mut sql, organization_id, selector);
Ok(self.exec().execute(sql).await? > 0)
}
}