Skip to main content

alibi_plugins/organization/
policy.rs

1//! Application-owned organization creation policies, evaluated on the persisted user.
2use alibi_core::{AuthResult, wire::UserView};
3use async_trait::async_trait;
4
5/// Optional asynchronous overrides for the fixed creation settings.
6///
7/// `None` uses the corresponding fixed configuration. A limit override returns
8/// `Some(true)` when the user has reached the limit, rather than when creation is allowed.
9#[async_trait]
10pub trait OrganizationCreationPolicy: std::fmt::Debug + Send + Sync {
11    async fn allow_creation(&self, _user: &UserView) -> AuthResult<Option<bool>> {
12        Ok(None)
13    }
14    async fn limit_reached(&self, _user: &UserView) -> AuthResult<Option<bool>> {
15        Ok(None)
16    }
17}
18
19use super::types::OrganizationResponse;
20use std::sync::Arc;
21
22/// One immutable membership policy, shared by trusted addition and invitation admission.
23#[derive(Debug, Clone)]
24pub enum MembershipLimit {
25    Fixed(f64),
26    Resolver(Arc<dyn OrganizationMembershipLimitResolver>),
27}
28
29/// Evaluated after the actual member count and organization lookup, over the
30/// target user and raw stored organization. Read pages never invoke this callback.
31#[async_trait]
32pub trait OrganizationMembershipLimitResolver: std::fmt::Debug + Send + Sync {
33    async fn maximum_members(
34        &self,
35        user: &UserView,
36        organization: &OrganizationResponse,
37    ) -> AuthResult<f64>;
38}
39
40pub(crate) fn truthy_number(value: f64) -> bool {
41    value != 0.0 && !value.is_nan()
42}
43
44pub(crate) fn read_page_limit(policy: Option<&MembershipLimit>) -> f64 {
45    match policy {
46        Some(MembershipLimit::Fixed(value)) if truthy_number(*value) => *value,
47        _ => 100.0,
48    }
49}
50
51pub(crate) async fn admission_limit(
52    policy: Option<&MembershipLimit>,
53    user: &UserView,
54    organization: &OrganizationResponse,
55) -> AuthResult<f64> {
56    match policy {
57        Some(MembershipLimit::Resolver(resolver)) => {
58            resolver.maximum_members(user, organization).await
59        }
60        _ => Ok(read_page_limit(policy)),
61    }
62}