Skip to main content

alibi_plugins/organization/hooks/
member.rs

1use crate::organization::OrganizationMemberCreatePatch;
2use crate::organization::types::OrganizationMemberRemovalSnapshot;
3use crate::organization::types::OrganizationResponse;
4use alibi_core::AuthResult;
5use alibi_core::Member;
6use alibi_core::wire::UserView;
7use async_trait::async_trait;
8
9/// The source callback draft has no generated ID or creation timestamp.
10#[derive(Debug, Clone)]
11pub struct OrganizationMemberAdditionDraft {
12    pub user_id: String,
13    pub organization_id: String,
14    pub role: String,
15    pub team_id: Option<String>,
16}
17
18/// Target user and raw stored organization after all initial admission checks.
19/// There is no invented actor or HTTP request in this server-only callback.
20#[derive(Debug, Clone)]
21pub struct OrganizationMemberAdditionContext {
22    pub member: OrganizationMemberAdditionDraft,
23    pub user: UserView,
24    pub organization: OrganizationResponse,
25}
26
27/// The persisted member after optional team admission, with original snapshots.
28#[derive(Debug, Clone)]
29pub struct OrganizationMemberAddedContext {
30    pub member: Member,
31    pub user: UserView,
32    pub organization: OrganizationResponse,
33}
34
35/// Admission phases are awaited separately.
36///
37/// Before errors prevent the member write; after errors retain successful member/team writes. Team
38/// failures clean up the new member and the original user's configured page of team memberships.
39/// Supported typed patches are trusted and are not revalidated. Arbitrary custom columns and
40/// direct mutation of JavaScript arguments remain adapter boundaries.
41#[async_trait]
42pub trait OrganizationMemberAdditionHooks: std::fmt::Debug + Send + Sync {
43    async fn before_add_member(
44        &self,
45        _context: &OrganizationMemberAdditionContext,
46    ) -> AuthResult<Option<OrganizationMemberCreatePatch>> {
47        Ok(None)
48    }
49
50    async fn after_add_member(&self, _context: &OrganizationMemberAddedContext) -> AuthResult<()> {
51        Ok(())
52    }
53}
54
55/// The original target membership, target user and raw stored organization.
56///
57/// Email selection includes the adapter's joined user in member; ID selection
58/// omits it. These are target snapshots, not invented actor/request arguments.
59#[derive(Debug, Clone)]
60pub struct OrganizationMemberRemovalContext {
61    pub member: OrganizationMemberRemovalSnapshot,
62    pub user: UserView,
63    pub organization: OrganizationResponse,
64}
65
66/// Trusted callbacks run after authorization and related-row resolution.
67///
68/// Before errors prevent ordinary deletion; after errors retain committed deletion and
69/// current-session selection clearing. Independent callback writes remain real. The lifecycle has
70/// no enclosing transaction; the contextual adapter deletion does. Returned patches are not part
71/// of the source removal callback contract.
72#[async_trait]
73pub trait OrganizationMemberRemovalHooks: std::fmt::Debug + Send + Sync {
74    async fn before_remove(&self, _context: &OrganizationMemberRemovalContext) -> AuthResult<()> {
75        Ok(())
76    }
77    async fn after_remove(&self, _context: &OrganizationMemberRemovalContext) -> AuthResult<()> {
78        Ok(())
79    }
80}
81
82/// Original target membership, normalized requested role and target user.
83/// The organization uses the adapter's raw stored metadata projection.
84#[derive(Debug, Clone)]
85pub struct OrganizationMemberRoleContext {
86    pub member: Member,
87    pub new_role: String,
88    pub user: UserView,
89    pub organization: OrganizationResponse,
90}
91
92/// Updated member and original role, target user and organization snapshots.
93#[derive(Debug, Clone)]
94pub struct OrganizationMemberRoleUpdatedContext {
95    pub member: Member,
96    pub previous_role: String,
97    pub user: UserView,
98    pub organization: OrganizationResponse,
99}
100
101/// A nonempty role overrides the authorized initial role without revalidation.
102/// Empty or missing values retain the normalized initial role, as in source.
103#[derive(Debug, Clone, Default)]
104pub struct OrganizationMemberRolePatch {
105    pub role: Option<String>,
106}
107
108/// Trusted application callbacks execute after role authorization/validation.
109///
110/// Before errors prevent the adapter write; after errors retain it. The lifecycle
111/// is not wrapped in a transaction. Contexts contain the target user, not actor.
112#[async_trait]
113pub trait OrganizationMemberRoleHooks: std::fmt::Debug + Send + Sync {
114    async fn before_update(
115        &self,
116        _context: &OrganizationMemberRoleContext,
117    ) -> AuthResult<Option<OrganizationMemberRolePatch>> {
118        Ok(None)
119    }
120    async fn after_update(
121        &self,
122        _context: &OrganizationMemberRoleUpdatedContext,
123    ) -> AuthResult<()> {
124        Ok(())
125    }
126}