Skip to main content

openauth_plugins/organization/
options.rs

1use openauth_core::db::TableOptions;
2use serde_json::{json, Value};
3
4use super::hooks::OrganizationHooks;
5use super::{Invitation, Member, Organization};
6use std::sync::Arc;
7
8pub type SendInvitationEmailHook =
9    Arc<dyn Fn(&InvitationEmail) -> Result<(), openauth_core::error::OpenAuthError> + Send + Sync>;
10
11#[derive(Clone)]
12pub struct OrganizationOptions {
13    pub allow_user_to_create_organization: bool,
14    pub organization_limit: Option<usize>,
15    pub creator_role: String,
16    pub membership_limit: usize,
17    pub invitation_expires_in: i64,
18    pub invitation_limit: usize,
19    pub cancel_pending_invitations_on_re_invite: bool,
20    pub require_email_verification_on_invitation: bool,
21    pub disable_organization_deletion: bool,
22    pub hooks: OrganizationHooks,
23    pub send_invitation_email: Option<SendInvitationEmailHook>,
24    pub teams: TeamOptions,
25    pub dynamic_access_control: DynamicAccessControlOptions,
26    pub custom_roles: std::collections::BTreeMap<String, serde_json::Value>,
27    pub schema: OrganizationSchemaOptions,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct TeamOptions {
32    pub enabled: bool,
33    pub create_default_team: bool,
34    pub maximum_teams: Option<usize>,
35    pub maximum_members_per_team: Option<usize>,
36    pub allow_removing_all_teams: bool,
37}
38
39#[derive(Clone, Debug, Default, PartialEq, Eq)]
40pub struct DynamicAccessControlOptions {
41    pub enabled: bool,
42    pub maximum_roles_per_organization: Option<usize>,
43}
44
45#[derive(Clone, Debug, Default, PartialEq, Eq)]
46pub struct OrganizationSchemaOptions {
47    pub organization: TableOptions,
48    pub member: TableOptions,
49    pub invitation: TableOptions,
50    pub team: TableOptions,
51    pub team_member: TableOptions,
52    pub organization_role: TableOptions,
53}
54
55#[derive(Debug, Clone)]
56pub struct InvitationEmail {
57    pub id: String,
58    pub role: String,
59    pub email: String,
60    pub organization: Organization,
61    pub invitation: Invitation,
62    pub inviter: Member,
63}
64
65impl Default for OrganizationOptions {
66    fn default() -> Self {
67        Self {
68            allow_user_to_create_organization: true,
69            organization_limit: None,
70            creator_role: "owner".to_owned(),
71            membership_limit: 100,
72            invitation_expires_in: 60 * 60 * 48,
73            invitation_limit: 100,
74            cancel_pending_invitations_on_re_invite: false,
75            require_email_verification_on_invitation: false,
76            disable_organization_deletion: false,
77            hooks: OrganizationHooks::default(),
78            send_invitation_email: None,
79            teams: TeamOptions::default(),
80            dynamic_access_control: DynamicAccessControlOptions::default(),
81            custom_roles: std::collections::BTreeMap::new(),
82            schema: OrganizationSchemaOptions::default(),
83        }
84    }
85}
86
87impl Default for TeamOptions {
88    fn default() -> Self {
89        Self {
90            enabled: false,
91            create_default_team: true,
92            maximum_teams: None,
93            maximum_members_per_team: None,
94            allow_removing_all_teams: false,
95        }
96    }
97}
98
99impl OrganizationOptions {
100    pub fn builder() -> OrganizationOptionsBuilder {
101        OrganizationOptionsBuilder::default()
102    }
103
104    pub(crate) fn to_metadata(&self) -> Value {
105        json!({
106            "allowUserToCreateOrganization": self.allow_user_to_create_organization,
107            "organizationLimit": self.organization_limit,
108            "creatorRole": self.creator_role,
109            "membershipLimit": self.membership_limit,
110            "invitationExpiresIn": self.invitation_expires_in,
111            "invitationLimit": self.invitation_limit,
112            "cancelPendingInvitationsOnReInvite": self.cancel_pending_invitations_on_re_invite,
113            "requireEmailVerificationOnInvitation": self.require_email_verification_on_invitation,
114            "disableOrganizationDeletion": self.disable_organization_deletion,
115            "teams": {
116                "enabled": self.teams.enabled,
117                "defaultTeam": { "enabled": self.teams.create_default_team },
118                "maximumTeams": self.teams.maximum_teams,
119                "maximumMembersPerTeam": self.teams.maximum_members_per_team,
120                "allowRemovingAllTeams": self.teams.allow_removing_all_teams,
121            },
122            "dynamicAccessControl": {
123                "enabled": self.dynamic_access_control.enabled,
124                "maximumRolesPerOrganization": self.dynamic_access_control.maximum_roles_per_organization,
125            },
126            "customRoles": self.custom_roles,
127        })
128    }
129}
130
131#[derive(Clone, Default)]
132pub struct OrganizationOptionsBuilder {
133    options: OrganizationOptions,
134}
135
136impl OrganizationOptionsBuilder {
137    pub fn allow_user_to_create_organization(mut self, allow: bool) -> Self {
138        self.options.allow_user_to_create_organization = allow;
139        self
140    }
141
142    pub fn organization_limit(mut self, limit: usize) -> Self {
143        self.options.organization_limit = Some(limit);
144        self
145    }
146
147    pub fn creator_role(mut self, role: impl Into<String>) -> Self {
148        self.options.creator_role = role.into();
149        self
150    }
151
152    pub fn membership_limit(mut self, limit: usize) -> Self {
153        self.options.membership_limit = limit;
154        self
155    }
156
157    pub fn invitation_expires_in(mut self, seconds: i64) -> Self {
158        self.options.invitation_expires_in = seconds;
159        self
160    }
161
162    pub fn invitation_limit(mut self, limit: usize) -> Self {
163        self.options.invitation_limit = limit;
164        self
165    }
166
167    pub fn cancel_pending_invitations_on_re_invite(mut self, cancel: bool) -> Self {
168        self.options.cancel_pending_invitations_on_re_invite = cancel;
169        self
170    }
171
172    pub fn require_email_verification_on_invitation(mut self, require: bool) -> Self {
173        self.options.require_email_verification_on_invitation = require;
174        self
175    }
176
177    pub fn disable_organization_deletion(mut self, disable: bool) -> Self {
178        self.options.disable_organization_deletion = disable;
179        self
180    }
181
182    pub fn hooks(mut self, hooks: OrganizationHooks) -> Self {
183        self.options.hooks = hooks;
184        self
185    }
186
187    pub fn send_invitation_email(mut self, hook: SendInvitationEmailHook) -> Self {
188        self.options.send_invitation_email = Some(hook);
189        self
190    }
191
192    pub fn teams(mut self, teams: TeamOptions) -> Self {
193        self.options.teams = teams;
194        self
195    }
196
197    pub fn dynamic_access_control(mut self, options: DynamicAccessControlOptions) -> Self {
198        self.options.dynamic_access_control = options;
199        self
200    }
201
202    pub fn custom_role(mut self, role: impl Into<String>, permissions: serde_json::Value) -> Self {
203        self.options.custom_roles.insert(role.into(), permissions);
204        self
205    }
206
207    pub fn schema(mut self, schema: OrganizationSchemaOptions) -> Self {
208        self.options.schema = schema;
209        self
210    }
211
212    pub fn build(self) -> OrganizationOptions {
213        self.options
214    }
215}