alibi_core/store/stateless/
users.rs1use crate::store::UserStore;
2use crate::store::stateless::{StatelessSchema, StatelessStore, members};
3use crate::{AuthError, AuthResult, CreateUser, ListUsersParams, UpdateUser, UserView};
4use async_trait::async_trait;
5use chrono::Utc;
6#[async_trait]
7impl UserStore<StatelessSchema> for StatelessStore {
8 async fn create_user(&self, mut create_user: CreateUser) -> AuthResult<UserView> {
9 create_user.email = create_user.email.map(|email| email.to_lowercase());
10 UserStore::<StatelessSchema>::create_user_prepared(
11 self,
12 crate::user_validation::PreparedUserCreation::from_data(create_user),
13 )
14 .await
15 }
16
17 async fn create_user_prepared(
18 &self,
19 prepared: crate::user_validation::PreparedUserCreation,
20 ) -> AuthResult<UserView> {
21 let (create_user, defaults) = prepared.into_parts();
22 let mut create_user = defaults.apply(create_user)?;
23 create_user
24 .additional_fields
25 .apply_adapter_transforms_async()
26 .await?;
27 let now = Utc::now();
28 let id = create_user
29 .id
30 .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
31 let mut omitted_fields = std::collections::BTreeSet::new();
32 for (name, absent) in [
33 ("name", create_user.name.is_none()),
34 ("email", create_user.email.is_none()),
35 ("image", create_user.image.is_none()),
36 ("username", create_user.username.is_none()),
37 ("displayUsername", create_user.display_username.is_none()),
38 ] {
39 if absent && !create_user.additional_fields.contains_key(name) {
40 _ = omitted_fields.insert(name.to_owned());
41 }
42 }
43 let username = create_user.username.map(|username| username.to_lowercase());
44 let user = UserView {
45 omitted_fields,
46 id: id.clone(),
47 name: create_user.name,
48 email: create_user.email,
49 email_verified: create_user.email_verified.unwrap_or(false),
50 image: create_user.image,
51 created_at: create_user.created_at.unwrap_or(now),
52 updated_at: create_user.updated_at.unwrap_or(now),
53 username,
54 display_username: create_user.display_username,
55 two_factor_enabled: create_user.two_factor_enabled,
56 role: create_user.role,
57 banned: create_user.banned,
58 ban_reason: None,
59 ban_expires: None,
60 metadata: create_user
61 .metadata
62 .unwrap_or_else(|| serde_json::json!({})),
63 is_anonymous: create_user.is_anonymous,
64 phone_number: create_user.phone_number,
65 phone_number_verified: create_user.phone_number_verified,
66 last_login_method: create_user.last_login_method,
67 extension_fields: create_user
68 .additional_fields
69 .into_iter()
70 .map(|(key, value)| value.to_json_value().map(|value| (key, value)))
71 .collect::<Result<_, _>>()?,
72 };
73 let mut state = self.lock()?;
74 if state.users.contains_key(&id)
75 || state
76 .users
77 .values()
78 .any(|existing| user.email.is_some() && existing.email == user.email)
79 {
80 return Err(AuthError::bad_request("User already exists"));
81 }
82 _ = state.users.insert(id, user.clone());
83 Ok(user)
84 }
85
86 async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<UserView>> {
87 Ok(self.lock()?.users.get(id).cloned())
88 }
89
90 async fn list_users_by_ids(&self, ids: &[String]) -> AuthResult<Vec<UserView>> {
91 let state = self.lock()?;
92 Ok(ids
93 .iter()
94 .filter_map(|id| state.users.get(id).cloned())
95 .collect())
96 }
97
98 async fn list_users_by_ids_page(
99 &self,
100 ids: &[String],
101 limit: f64,
102 ) -> AuthResult<Vec<UserView>> {
103 let mut users: Vec<_> = self
104 .lock()?
105 .users
106 .values()
107 .filter(|user| ids.contains(&user.id))
108 .cloned()
109 .collect();
110 users.truncate(members::slice_index(limit, users.len()));
111 Ok(users)
112 }
113
114 async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<UserView>> {
115 Ok(self
116 .lock()?
117 .users
118 .values()
119 .find(|user| user.email.as_deref() == Some(&email.to_lowercase()))
120 .cloned())
121 }
122
123 async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<UserView>> {
124 let normalized = username.to_lowercase();
125 Ok(self
126 .lock()?
127 .users
128 .values()
129 .find(|user| user.username.as_deref() == Some(&normalized))
130 .cloned())
131 }
132
133 async fn get_user_by_phone_number(&self, phone_number: &str) -> AuthResult<Option<UserView>> {
134 Ok(self
135 .lock()?
136 .users
137 .values()
138 .find(|user| user.phone_number.as_deref() == Some(phone_number))
139 .cloned())
140 }
141
142 async fn update_user(&self, id: &str, mut update: UpdateUser) -> AuthResult<UserView> {
143 update
144 .additional_fields
145 .apply_adapter_transforms_async()
146 .await?;
147 let mut state = self.lock()?;
148 let user = state.users.get_mut(id).ok_or(AuthError::UserNotFound)?;
149 if let Some(email) = update.email {
150 user.email = Some(email.to_lowercase());
151 }
152 if let Some(name) = update.name {
153 user.name = Some(name);
154 }
155 if let Some(image) = update.image {
156 user.image = Some(image);
157 }
158 if update.provider_image == Some(serde_json::Value::Null) {
159 user.image = None;
160 }
161 if let Some(email_verified) = update.email_verified {
162 user.email_verified = email_verified;
163 }
164 if let Some(username) = update.username {
165 user.username = Some(username.to_lowercase());
166 }
167 if let Some(display_username) = update.display_username {
168 user.display_username = Some(display_username);
169 }
170 if let Some(role) = update.role {
171 user.role = Some(role);
172 }
173 if let Some(banned) = update.banned {
174 user.banned = Some(banned);
175 if !banned {
176 user.ban_reason = None;
177 user.ban_expires = None;
178 }
179 }
180 if let Some(ban_reason) = update.ban_reason {
181 user.ban_reason = Some(ban_reason);
182 }
183 if let Some(ban_expires) = update.ban_expires {
184 user.ban_expires = ban_expires;
185 }
186 if let Some(two_factor_enabled) = update.two_factor_enabled {
187 user.two_factor_enabled = Some(two_factor_enabled);
188 }
189 if let Some(metadata) = update.metadata {
190 user.metadata = metadata;
191 }
192 if let Some(is_anonymous) = update.is_anonymous {
193 user.is_anonymous = Some(is_anonymous);
194 }
195 if let Some(phone_number) = update.phone_number {
196 user.phone_number = phone_number;
197 }
198 if let Some(phone_number_verified) = update.phone_number_verified {
199 user.phone_number_verified = Some(phone_number_verified);
200 }
201 if let Some(last_login_method) = update.last_login_method {
202 user.last_login_method = last_login_method;
203 }
204 for (key, value) in update.additional_fields {
205 _ = user.extension_fields.insert(key, value.to_json_value()?);
206 }
207 for (name, present) in [
208 ("name", user.name.is_some()),
209 ("email", user.email.is_some()),
210 ("image", user.image.is_some()),
211 ("username", user.username.is_some()),
212 ("displayUsername", user.display_username.is_some()),
213 ] {
214 if present {
215 _ = user.omitted_fields.remove(name);
216 }
217 }
218 user.updated_at = Utc::now();
219 Ok(user.clone())
220 }
221
222 async fn delete_user(&self, id: &str) -> AuthResult<()> {
223 _ = self.lock()?.users.shift_remove(id);
224 Ok(())
225 }
226
227 async fn list_users(&self, _params: ListUsersParams) -> AuthResult<(Vec<UserView>, usize)> {
228 let users: Vec<_> = self.lock()?.users.values().cloned().collect();
229 Ok(crate::user_query::apply_list_users(users, &_params))
230 }
231}