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