1use std::collections::HashMap;
16
17use serde::{Deserialize, Serialize};
18use serde_json::Value;
19
20use crate::client::{get_owner, Client, PostBody, Response};
21use crate::error::Result;
22use crate::order::ProductInfo;
23use crate::organization::MfaItem;
24use crate::permission::Permission;
25use crate::role::Role;
26use crate::serde_util::null_to_default;
27
28pub const MFA_RECOVERY_CODES_SESSION: &str = "mfa_recovery_codes";
30
31#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase", default)]
33pub struct ManagedAccount {
34 pub application: String,
35 pub username: String,
36 pub password: String,
37 pub signin_url: String,
38}
39
40#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
41#[serde(rename_all = "camelCase", default)]
42pub struct MfaAccount {
43 pub account_name: String,
44 pub issuer: String,
45 pub secret_key: String,
46 pub origin: String,
47}
48
49#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
50#[serde(rename_all = "camelCase", default)]
51pub struct Address {
52 pub tag: String,
53 pub line1: String,
54 pub line2: String,
55 pub city: String,
56 pub state: String,
57 pub zip_code: String,
58 pub region: String,
59}
60
61#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
62#[serde(rename_all = "camelCase", default)]
63pub struct FaceId {
64 pub name: String,
65 #[serde(deserialize_with = "null_to_default")]
66 pub face_id_data: Vec<f64>,
67 pub image_url: String,
68}
69
70#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
71#[serde(rename_all = "camelCase", default)]
72pub struct MfaProps {
73 pub enabled: bool,
74 pub is_preferred: bool,
75 pub mfa_type: String,
76 pub secret: String,
77 pub country_code: String,
78 pub url: String,
79 #[serde(deserialize_with = "null_to_default")]
80 pub recovery_codes: Vec<String>,
81 pub mfa_remember_in_hours: i32,
82}
83
84#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
86#[serde(default)]
87pub struct Userinfo {
88 pub sub: String,
89 pub iss: String,
90 pub aud: String,
91 #[serde(rename = "preferred_username")]
92 pub name: String,
93 #[serde(rename = "name")]
94 pub display_name: String,
95 pub email: String,
96 pub email_verified: bool,
97 #[serde(rename = "picture")]
98 pub avatar: String,
99 pub address: String,
100 pub phone: String,
101 pub real_name: String,
102 pub is_verified: bool,
103 #[serde(deserialize_with = "null_to_default")]
104 pub groups: Vec<String>,
105 #[serde(deserialize_with = "null_to_default")]
106 pub roles: Vec<String>,
107 #[serde(deserialize_with = "null_to_default")]
108 pub permissions: Vec<String>,
109}
110
111#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase", default)]
113pub struct ConsentRecord {
114 pub application: String,
116 #[serde(deserialize_with = "null_to_default")]
117 pub granted_scopes: Vec<String>,
118}
119
120#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase", default)]
122pub struct ThirdPartyLink {
123 pub owner: String,
124 pub user_name: String,
125 pub provider_name: String,
126 pub provider_id: String,
127 pub created_time: String,
128}
129
130#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase", default)]
132pub struct ScopeDescription {
133 pub scope: String,
134 pub display_name: String,
135 pub description: String,
136}
137
138#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
141#[serde(rename_all = "camelCase", default)]
142pub struct User {
143 pub owner: String,
144 pub name: String,
145 pub created_time: String,
146 pub updated_time: String,
147 pub deleted_time: String,
148
149 pub id: String,
150 pub external_id: String,
151 pub r#type: String,
152 pub password: String,
153 pub password_salt: String,
154 pub password_type: String,
155 pub display_name: String,
156 pub first_name: String,
157 pub last_name: String,
158 pub avatar: String,
159 pub avatar_type: String,
160 pub permanent_avatar: String,
161 pub email: String,
162 pub email_verified: bool,
163 pub phone: String,
164 pub country_code: String,
165 pub region: String,
166 pub location: String,
167 #[serde(deserialize_with = "null_to_default")]
168 pub address: Vec<String>,
169 #[serde(deserialize_with = "null_to_default")]
170 pub addresses: Vec<Address>,
171 pub affiliation: String,
172 pub title: String,
173 pub id_card_type: String,
174 pub id_card: String,
175 pub real_name: String,
176 pub is_verified: bool,
177 pub homepage: String,
178 pub bio: String,
179 pub tag: String,
180 pub language: String,
181 pub gender: String,
182 pub birthday: String,
183 pub education: String,
184 pub score: i32,
185 pub karma: i32,
186 pub ranking: i32,
187 pub balance: f64,
188 pub balance_credit: f64,
189 pub currency: String,
190 pub balance_currency: String,
191 pub is_default_avatar: bool,
192 pub is_online: bool,
193 pub is_admin: bool,
194 pub is_forbidden: bool,
195 pub is_deleted: bool,
196 pub signup_application: String,
197 pub hash: String,
198 pub pre_hash: String,
199 pub register_type: String,
200 pub register_source: String,
201 pub access_token: String,
202 pub original_token: String,
203 pub original_refresh_token: String,
204
205 pub created_ip: String,
206 pub last_signin_time: String,
207 pub last_signin_ip: String,
208
209 pub github: String,
210 pub google: String,
211 pub qq: String,
212 pub wechat: String,
213 pub facebook: String,
214 pub dingtalk: String,
215 pub weibo: String,
216 pub gitee: String,
217 pub linkedin: String,
218 pub wecom: String,
219 pub lark: String,
220 pub gitlab: String,
221 pub adfs: String,
222 pub baidu: String,
223 pub alipay: String,
224 pub casdoor: String,
225 pub infoflow: String,
226 pub apple: String,
227 pub azuread: String,
228 pub azureadb2c: String,
229 pub slack: String,
230 pub steam: String,
231 pub bilibili: String,
232 pub okta: String,
233 pub douyin: String,
234 pub kwai: String,
235 pub line: String,
236 pub amazon: String,
237 pub auth0: String,
238 pub battlenet: String,
239 pub bitbucket: String,
240 #[serde(rename = "box")]
241 pub r#box: String,
242 pub cloudfoundry: String,
243 pub dailymotion: String,
244 pub deezer: String,
245 pub digitalocean: String,
246 pub discord: String,
247 pub dropbox: String,
248 pub eveonline: String,
249 pub fitbit: String,
250 pub gitea: String,
251 pub heroku: String,
252 pub influxcloud: String,
253 pub instagram: String,
254 pub intercom: String,
255 pub kakao: String,
256 pub lastfm: String,
257 pub mailru: String,
258 pub meetup: String,
259 pub microsoftonline: String,
260 pub naver: String,
261 pub nextcloud: String,
262 pub onedrive: String,
263 pub oura: String,
264 pub patreon: String,
265 pub paypal: String,
266 pub salesforce: String,
267 pub shopify: String,
268 pub soundcloud: String,
269 pub spotify: String,
270 pub strava: String,
271 pub stripe: String,
272 pub telegram: String,
273 pub tiktok: String,
274 pub tumblr: String,
275 pub twitch: String,
276 pub twitter: String,
277 pub typetalk: String,
278 pub uber: String,
279 pub vk: String,
280 pub wepay: String,
281 pub xero: String,
282 pub yahoo: String,
283 pub yammer: String,
284 pub yandex: String,
285 pub zoom: String,
286 pub metamask: String,
287 pub web3onboard: String,
288 pub oidc: String,
289 pub custom: String,
290 pub custom2: String,
291 pub custom3: String,
292 pub custom4: String,
293 pub custom5: String,
294 pub custom6: String,
295 pub custom7: String,
296 pub custom8: String,
297 pub custom9: String,
298 pub custom10: String,
299
300 pub webauthn_credentials: Value,
303 pub preferred_mfa_type: String,
304 #[serde(deserialize_with = "null_to_default")]
305 pub recovery_codes: Vec<String>,
306 pub totp_secret: String,
307 pub mfa_phone_enabled: bool,
308 pub mfa_email_enabled: bool,
309 pub mfa_radius_enabled: bool,
310 pub mfa_radius_username: String,
311 pub mfa_radius_provider: String,
312 pub mfa_push_enabled: bool,
313 pub mfa_push_receiver: String,
314 pub mfa_push_provider: String,
315 #[serde(deserialize_with = "null_to_default")]
316 pub multi_factor_auths: Vec<MfaProps>,
317 pub invitation: String,
318 pub invitation_code: String,
319 #[serde(deserialize_with = "null_to_default")]
320 pub face_ids: Vec<FaceId>,
321 #[serde(deserialize_with = "null_to_default")]
322 pub cart: Vec<ProductInfo>,
323
324 pub ldap: String,
325 pub uid_number: i32,
326 #[serde(deserialize_with = "null_to_default")]
327 pub properties: HashMap<String, String>,
328
329 #[serde(deserialize_with = "null_to_default")]
330 pub third_party_links: Vec<ThirdPartyLink>,
331
332 #[serde(deserialize_with = "null_to_default")]
333 pub roles: Vec<Role>,
334 #[serde(deserialize_with = "null_to_default")]
335 pub permissions: Vec<Permission>,
336 #[serde(deserialize_with = "null_to_default")]
337 pub groups: Vec<String>,
338
339 pub last_change_password_time: String,
340 pub last_signin_wrong_time: String,
341 pub signin_wrong_times: i32,
342
343 #[serde(deserialize_with = "null_to_default")]
344 pub managed_accounts: Vec<ManagedAccount>,
345 #[serde(deserialize_with = "null_to_default")]
346 pub mfa_accounts: Vec<MfaAccount>,
347 #[serde(deserialize_with = "null_to_default")]
348 pub mfa_items: Vec<MfaItem>,
349 pub mfa_remember_deadline: String,
350 pub need_update_password: bool,
351 pub ip_whitelist: String,
352 #[serde(deserialize_with = "null_to_default")]
353 pub application_scopes: Vec<ConsentRecord>,
354}
355
356impl User {
357 pub fn get_id(&self) -> String {
359 format!("{}/{}", self.owner, self.name)
360 }
361}
362
363impl Client {
364 pub async fn get_global_users(&self) -> Result<Vec<User>> {
366 self.get_list("get-global-users", &[]).await
367 }
368
369 pub async fn get_users(&self) -> Result<Vec<User>> {
371 self.get_list("get-users", &[("owner", &self.config.organization_name)])
372 .await
373 }
374
375 pub async fn get_sorted_users(&self, sorter: &str, limit: i32) -> Result<Vec<User>> {
378 self.get_list(
379 "get-sorted-users",
380 &[
381 ("owner", &self.config.organization_name),
382 ("sorter", sorter),
383 ("limit", &limit.to_string()),
384 ],
385 )
386 .await
387 }
388
389 pub async fn get_pagination_users(
392 &self,
393 p: i32,
394 page_size: i32,
395 query: &[(&str, &str)],
396 ) -> Result<(Vec<User>, i32)> {
397 self.get_pagination(
398 "get-users",
399 &self.config.organization_name,
400 p,
401 page_size,
402 query,
403 )
404 .await
405 }
406
407 pub async fn get_user_count(&self, is_online: &str) -> Result<i32> {
410 let url = self.get_url(
411 "get-user-count",
412 &[
413 ("owner", &self.config.organization_name),
414 ("isOnline", is_online),
415 ],
416 );
417
418 let response = self.do_get_response(&url).await?;
419 Ok(serde_json::from_value(response.data)?)
420 }
421
422 pub async fn get_user(&self, name: &str) -> Result<Option<User>> {
425 self.get_object("get-user", &[("id", &self.get_id(name))])
426 .await
427 }
428
429 pub async fn get_account(&self) -> Result<Option<User>> {
434 self.get_object("get-account", &[]).await
435 }
436
437 pub async fn get_user_by_email(&self, email: &str) -> Result<Option<User>> {
439 self.get_object(
440 "get-user",
441 &[("owner", &self.config.organization_name), ("email", email)],
442 )
443 .await
444 }
445
446 pub async fn get_user_by_phone(&self, phone: &str) -> Result<Option<User>> {
448 self.get_object(
449 "get-user",
450 &[("owner", &self.config.organization_name), ("phone", phone)],
451 )
452 .await
453 }
454
455 pub async fn get_user_by_user_id(&self, user_id: &str) -> Result<Option<User>> {
457 self.get_object(
458 "get-user",
459 &[
460 ("owner", &self.config.organization_name),
461 ("userId", user_id),
462 ],
463 )
464 .await
465 }
466
467 pub async fn set_password(
470 &self,
471 owner: &str,
472 name: &str,
473 old_password: &str,
474 new_password: &str,
475 ) -> Result<bool> {
476 let fields = HashMap::from([
477 ("userOwner".to_string(), owner.to_string()),
478 ("userName".to_string(), name.to_string()),
479 ("oldPassword".to_string(), old_password.to_string()),
480 ("newPassword".to_string(), new_password.to_string()),
481 ]);
482
483 let response = self
484 .do_post("set-password", &[], PostBody::Form(fields))
485 .await?;
486
487 Ok(response.status == "ok")
488 }
489
490 pub async fn add_user(&self, user: &User) -> Result<bool> {
492 Ok(self.modify_user("add-user", user, &[]).await?.1)
493 }
494
495 pub async fn update_user(&self, user: &User) -> Result<bool> {
497 Ok(self.modify_user("update-user", user, &[]).await?.1)
498 }
499
500 pub async fn update_user_for_columns(&self, user: &User, columns: &[&str]) -> Result<bool> {
502 Ok(self.modify_user("update-user", user, columns).await?.1)
503 }
504
505 pub async fn update_user_by_id(&self, id: &str, user: &User) -> Result<bool> {
507 Ok(self
508 .modify_user_by_id("update-user", id, user, &[])
509 .await?
510 .1)
511 }
512
513 pub async fn update_user_by_user_id(
515 &self,
516 owner: &str,
517 user_id: &str,
518 user: &User,
519 ) -> Result<bool> {
520 let post_bytes = serde_json::to_vec(user)?;
521 let response = self
522 .do_post(
523 "update-user",
524 &[("owner", owner), ("userId", user_id)],
525 PostBody::Raw(post_bytes),
526 )
527 .await?;
528
529 Ok(response.data.as_str() == Some("Affected"))
530 }
531
532 pub async fn delete_user(&self, user: &User) -> Result<bool> {
534 Ok(self.modify_user("delete-user", user, &[]).await?.1)
535 }
536
537 pub async fn check_user_password(&self, user: &User) -> Result<bool> {
539 let (response, _) = self.modify_user("check-user-password", user, &[]).await?;
540 Ok(response.status == "ok")
541 }
542
543 async fn modify_user(
546 &self,
547 action: &str,
548 user: &User,
549 columns: &[&str],
550 ) -> Result<(Response, bool)> {
551 let owner = get_owner(&user.owner, &self.config.organization_name);
552 let id = format!("{}/{}", owner, user.name);
553
554 self.modify_user_by_id(action, &id, user, columns).await
555 }
556
557 async fn modify_user_by_id(
558 &self,
559 action: &str,
560 id: &str,
561 user: &User,
562 columns: &[&str],
563 ) -> Result<(Response, bool)> {
564 let mut user = user.clone();
565 user.owner = get_owner(&user.owner, &self.config.organization_name);
566
567 self.modify_object(action, id, &user, columns).await
568 }
569}