rustauth_plugins/organization/
limits.rs1use 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#[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#[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}