pub mod extension_common;
pub(crate) mod invitation;
pub(crate) mod member;
pub(crate) mod member_addition;
pub(crate) mod org;
pub(crate) mod org_input;
mod page;
pub(crate) mod role;
pub(crate) mod team;
mod validation;
pub(crate) mod invitation_acceptance;
use super::OrganizationConfig;
use super::types::{HasPermissionRequest, HasPermissionResponse};
use alibi_core::entity::{AuthMember, AuthSession, AuthUser};
use alibi_core::error::codes;
use alibi_core::error::{AuthError, AuthResult};
use alibi_core::plugin::AuthContext;
use alibi_core::types::{AuthRequest, AuthResponse};
pub(crate) async fn resolve_organization_id(
org_id: Option<&str>,
org_slug: Option<&str>,
session: &impl AuthSession,
ctx: &AuthContext<impl alibi_core::AuthSchema>,
) -> AuthResult<String> {
if let Some(id) = org_id {
return Ok(id.to_owned());
}
if let Some(slug) = org_slug {
if let Some(org) = ctx.database.get_organization_by_slug(slug).await? {
use alibi_core::entity::AuthOrganization;
return Ok(org.id().to_string());
}
return Err(AuthError::not_found("Organization not found"));
}
session
.active_organization_id()
.map(ToOwned::to_owned)
.ok_or_else(|| AuthError::bad_request("No active organization"))
}
pub(crate) async fn has_permission_core(
body: &HasPermissionRequest,
user: &impl AuthUser,
session: &impl AuthSession,
config: &OrganizationConfig,
ctx: &AuthContext<impl alibi_core::AuthSchema>,
) -> AuthResult<HasPermissionResponse> {
let org_id = body
.organization_id
.as_deref()
.filter(|id| !id.is_empty())
.or_else(|| session.active_organization_id())
.filter(|id| !id.is_empty())
.ok_or_else(|| extension_common::org_error(400, codes::NO_ACTIVE_ORGANIZATION))?;
let member = ctx
.database
.get_member(org_id, &user.id())
.await?
.ok_or_else(|| {
extension_common::org_error(401, codes::USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION)
})?;
let required = body
.permissions
.iter()
.map(|(key, value)| (key.clone(), value.clone()))
.collect();
let has_all_permissions =
extension_common::has_permissions(member.role(), &required, config, ctx, org_id).await?;
Ok(HasPermissionResponse {
success: has_all_permissions,
error: None,
})
}
pub(crate) async fn handle_has_permission(
req: &AuthRequest,
ctx: &AuthContext<impl alibi_core::AuthSchema>,
config: &OrganizationConfig,
) -> AuthResult<AuthResponse> {
let input = match validation::body_object(req) {
Ok(value) => value,
Err(response) => return Ok(response),
};
let mut issues = validation::Issues::default();
let organization_id = issues
.take(validation::optional_string(
&input,
"organizationId",
"body.organizationId",
))
.flatten();
let canonical = validation::permissions(input.get("permissions"), "body.permissions").ok();
let legacy = validation::permissions(input.get("permission"), "body.permission").ok();
let permissions = match (canonical, legacy) {
(Some(_), Some(_)) => {
issues.push("[body] Invalid input: more than one option matched");
indexmap::IndexMap::default()
}
(None, None) => {
issues.push("[body] Invalid input");
indexmap::IndexMap::default()
}
(Some(permissions), None) => permissions,
(None, Some(_)) => indexmap::IndexMap::default(),
};
if let Some(response) = issues.response() {
return Ok(response);
}
let body = HasPermissionRequest {
organization_id,
permissions: permissions.into_iter().collect(),
};
let (user, session) = crate::helpers::ordinary_session(req, ctx).await?;
let response = has_permission_core(&body, &user, &session, config, ctx).await?;
Ok(AuthResponse::json(200, &response)?)
}