Skip to main content

rustauth_plugins/organization/
limits.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use rustauth_core::db::User;
6use rustauth_core::error::RustAuthError;
7
8use super::models::Organization;
9use super::options::OrganizationOptions;
10use super::store::OrganizationStore;
11
12pub type OrganizationLimitFuture =
13    Pin<Box<dyn Future<Output = Result<bool, RustAuthError>> + Send>>;
14pub type OrganizationLimitCallback = Arc<dyn Fn(User) -> OrganizationLimitFuture + Send + Sync>;
15
16pub type MembershipLimitFuture = Pin<Box<dyn Future<Output = Result<usize, RustAuthError>> + Send>>;
17pub type MembershipLimitCallback =
18    Arc<dyn Fn(MembershipLimitContext) -> MembershipLimitFuture + Send + Sync>;
19
20#[derive(Clone)]
21pub struct MembershipLimitContext {
22    pub user: User,
23    pub organization: Organization,
24}
25
26/// Maximum organizations a user may create.
27#[derive(Clone)]
28pub enum OrganizationLimit {
29    Fixed(usize),
30    Dynamic(OrganizationLimitCallback),
31}
32
33impl OrganizationLimit {
34    pub async fn is_reached(
35        &self,
36        user: &User,
37        current_count: usize,
38    ) -> Result<bool, RustAuthError> {
39        match self {
40            Self::Fixed(limit) => Ok(current_count >= *limit),
41            Self::Dynamic(callback) => (callback)(user.clone()).await,
42        }
43    }
44}
45
46/// Maximum members allowed in an organization.
47#[derive(Clone)]
48pub enum MembershipLimit {
49    Fixed(usize),
50    Dynamic(MembershipLimitCallback),
51}
52
53impl Default for MembershipLimit {
54    fn default() -> Self {
55        Self::Fixed(100)
56    }
57}
58
59impl MembershipLimit {
60    pub async fn resolve(&self, context: MembershipLimitContext) -> Result<usize, RustAuthError> {
61        match self {
62            Self::Fixed(limit) => Ok(*limit),
63            Self::Dynamic(callback) => (callback)(context).await,
64        }
65    }
66}
67
68pub async fn membership_limit_reached(
69    options: &OrganizationOptions,
70    store: &OrganizationStore<'_>,
71    organization_id: &str,
72    user: &User,
73) -> Result<bool, RustAuthError> {
74    let Some(organization) = store.organization_by_id(organization_id).await? else {
75        return Ok(false);
76    };
77    let limit = options
78        .membership_limit
79        .resolve(MembershipLimitContext {
80            user: user.clone(),
81            organization,
82        })
83        .await?;
84    Ok(store.count_members(organization_id).await? as usize >= limit)
85}