Skip to main content

alibi_core/store/stateless/
organizations.rs

1use super::*;
2
3fn patch(row: &mut Organization, update: UpdateOrganization) {
4    if let Some(name) = update.name {
5        row.name = name;
6    }
7    if let Some(slug) = update.slug {
8        row.slug = slug;
9    }
10    if let Some(logo) = update.logo {
11        row.logo = logo;
12    }
13    if let Some(metadata) = update.metadata {
14        row.metadata = Some(metadata);
15    }
16}
17
18#[async_trait]
19impl OrganizationStore for StatelessStore {
20    async fn create_organization(&self, data: CreateOrganization) -> AuthResult<Organization> {
21        let now = Utc::now();
22        let row = Organization {
23            additional_fields: Default::default(),
24            id: data.id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()),
25            name: data.name,
26            slug: data.slug,
27            logo: data.logo,
28            metadata: data.metadata,
29            created_at: now,
30            updated_at: now,
31        };
32        drop(
33            self.organization_state()?
34                .organizations
35                .insert(row.id.clone(), row.clone()),
36        );
37        Ok(row)
38    }
39    async fn get_organization_by_id(&self, id: &str) -> AuthResult<Option<Organization>> {
40        Ok(self.organization_state()?.organizations.get(id).cloned())
41    }
42    async fn get_organization_by_slug(&self, slug: &str) -> AuthResult<Option<Organization>> {
43        Ok(self
44            .organization_state()?
45            .organizations
46            .values()
47            .find(|row| row.slug == slug)
48            .cloned())
49    }
50    async fn list_organizations_by_ids(&self, ids: &[String]) -> AuthResult<Vec<Organization>> {
51        Ok(self
52            .organization_state()?
53            .organizations
54            .values()
55            .filter(|row| ids.contains(&row.id))
56            .cloned()
57            .collect())
58    }
59    async fn update_organization(
60        &self,
61        id: &str,
62        update: UpdateOrganization,
63    ) -> AuthResult<Organization> {
64        self.update_organization_if_present(id, update)
65            .await?
66            .ok_or_else(|| AuthError::not_found("Organization not found"))
67    }
68    async fn patch_organization_if_present(
69        &self,
70        id: &str,
71        update: UpdateOrganization,
72    ) -> AuthResult<Option<Organization>> {
73        let mut state = self.organization_state()?;
74        let Some(row) = state.organizations.get_mut(id) else {
75            return Ok(None);
76        };
77        // Memory adapter Object.assign accepts an empty patch. No synthesized timestamp.
78        patch(row, update);
79        Ok(Some(row.clone()))
80    }
81    async fn update_organization_if_present(
82        &self,
83        id: &str,
84        update: UpdateOrganization,
85    ) -> AuthResult<Option<Organization>> {
86        let mut state = self.organization_state()?;
87        let Some(row) = state.organizations.get_mut(id) else {
88            return Ok(None);
89        };
90        patch(row, update);
91        row.updated_at = Utc::now();
92        Ok(Some(row.clone()))
93    }
94    async fn delete_organization(&self, id: &str) -> AuthResult<()> {
95        let mut state = self.organization_state()?;
96        state.members.retain(|_, row| row.organization_id != id);
97        state.invitations.retain(|_, row| row.organization_id != id);
98        drop(state.organizations.shift_remove(id));
99        Ok(())
100    }
101    async fn list_user_organizations(&self, user_id: &str) -> AuthResult<Vec<Organization>> {
102        let state = self.organization_state()?;
103        Ok(state
104            .members
105            .values()
106            .filter(|row| row.user_id == user_id)
107            .take(self.find_many_limit)
108            .filter_map(|row| state.organizations.get(&row.organization_id).cloned())
109            .collect())
110    }
111}