casdoor_sdk_rust/user/
models.rs

1use std::{collections::HashMap, fmt::Display};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{utils::null_to_default, IsQueryArgs, Model, Permission, Role};
6
7#[derive(Serialize, Deserialize, Debug)]
8pub struct Userinfo {
9    sub: String,
10    iss: String,
11    aud: String,
12    #[serde(rename = "preferred_username", skip_serializing_if = "Option::is_none")]
13    name: Option<String>,
14    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
15    display_name: Option<String>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    email: Option<String>,
18    #[serde(rename = "email_verified", skip_serializing_if = "Option::is_none")]
19    email_verified: Option<bool>,
20    #[serde(rename = "picture", skip_serializing_if = "Option::is_none")]
21    avatar: Option<String>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    address: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    phone: Option<String>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    groups: Option<Vec<String>>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    roles: Option<Vec<String>>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    permissions: Option<Vec<String>>,
32}
33
34/// User info struct, defined in the SDK.
35
36#[derive(Debug, Clone, Serialize, Deserialize, Default)]
37#[serde(rename_all = "camelCase", default)]
38pub struct User {
39    pub owner: String,
40    pub name: String,
41    pub created_time: String,
42    pub updated_time: String,
43    pub deleted_time: String,
44    pub id: String,
45    pub external_id: String,
46    pub r#type: String,
47    pub password: String,
48    pub password_salt: String,
49    pub password_type: String,
50    pub display_name: String,
51    pub first_name: String,
52    pub last_name: String,
53    pub avatar: String,
54    pub avatar_type: String,
55    pub permanent_avatar: String,
56    pub email: String,
57    pub email_verified: bool,
58    pub phone: String,
59    pub country_code: String,
60    pub region: String,
61    pub location: String,
62    #[serde(deserialize_with = "null_to_default")]
63    pub address: Vec<String>,
64    pub affiliation: String,
65    pub title: String,
66    pub id_card_type: String,
67    pub id_card: String,
68    pub homepage: String,
69    pub bio: String,
70    pub tag: String,
71    pub language: String,
72    pub gender: String,
73    pub birthday: String,
74    pub education: String,
75    pub score: i32,
76    pub karma: i32,
77    pub ranking: i32,
78    pub balance: f64,
79    pub currency: String,
80    pub is_default_avatar: bool,
81    pub is_online: bool,
82    pub is_admin: bool,
83    pub is_forbidden: bool,
84    pub is_deleted: bool,
85    pub signup_application: String,
86    pub hash: String,
87    pub pre_hash: String,
88    pub access_key: String,
89    pub access_secret: String,
90    pub access_token: String,
91    pub created_ip: String,
92    pub last_signin_time: String,
93    pub last_signin_ip: String,
94    pub github: String,
95    pub google: String,
96    pub qq: String,
97    pub wechat: String,
98    pub facebook: String,
99    pub dingtalk: String,
100    pub weibo: String,
101    pub gitee: String,
102    pub linkedin: String,
103    pub wecom: String,
104    pub lark: String,
105    pub gitlab: String,
106    pub adfs: String,
107    pub baidu: String,
108    pub alipay: String,
109    pub casdoor: String,
110    pub infoflow: String,
111    pub apple: String,
112    pub azuread: String,
113    pub azureadb2c: String,
114    pub slack: String,
115    pub steam: String,
116    pub bilibili: String,
117    pub okta: String,
118    pub douyin: String,
119    pub line: String,
120    pub amazon: String,
121    pub auth0: String,
122    pub battlenet: String,
123    pub bitbucket: String,
124    pub r#box: String,
125    pub cloudfoundry: String,
126    pub dailymotion: String,
127    pub deezer: String,
128    pub digitalocean: String,
129    pub discord: String,
130    pub dropbox: String,
131    pub eveonline: String,
132    pub fitbit: String,
133    pub gitea: String,
134    pub heroku: String,
135    pub influxcloud: String,
136    pub instagram: String,
137    pub intercom: String,
138    pub kakao: String,
139    pub lastfm: String,
140    pub mailru: String,
141    pub meetup: String,
142    pub microsoftonline: String,
143    pub naver: String,
144    pub nextcloud: String,
145    pub onedrive: String,
146    pub oura: String,
147    pub patreon: String,
148    pub paypal: String,
149    pub salesforce: String,
150    pub shopify: String,
151    pub soundcloud: String,
152    pub spotify: String,
153    pub strava: String,
154    pub stripe: String,
155    pub tiktok: String,
156    pub tumblr: String,
157    pub twitch: String,
158    pub twitter: String,
159    pub typetalk: String,
160    pub uber: String,
161    pub vk: String,
162    pub wepay: String,
163    pub xero: String,
164    pub yahoo: String,
165    pub yammer: String,
166    pub yandex: String,
167    pub zoom: String,
168    pub metamask: String,
169    pub web3onboard: String,
170    pub custom: String,
171    #[serde(deserialize_with = "null_to_default")]
172    pub webauthn_credentials: Vec<String>,
173    pub preferred_mfa_type: String,
174    #[serde(deserialize_with = "null_to_default")]
175    pub recovery_codes: Vec<String>,
176    pub totp_secret: String,
177    pub mfa_phone_enabled: bool,
178    pub mfa_email_enabled: bool,
179    #[serde(deserialize_with = "null_to_default")]
180    pub multi_factor_auths: Vec<MfaProps>,
181    pub invitation: String,
182    pub invitation_code: String,
183    #[serde(deserialize_with = "null_to_default")]
184    pub face_ids: Vec<FaceId>,
185    pub ldap: String,
186    pub properties: HashMap<String, String>,
187    #[serde(deserialize_with = "null_to_default")]
188    pub roles: Vec<Role>,
189    #[serde(deserialize_with = "null_to_default")]
190    pub permissions: Vec<Permission>,
191    #[serde(deserialize_with = "null_to_default")]
192    pub groups: Vec<String>,
193    pub last_signin_wrong_time: String,
194    pub signin_wrong_times: i32,
195    #[serde(deserialize_with = "null_to_default")]
196    pub managed_accounts: Vec<ManagedAccount>,
197    #[serde(deserialize_with = "null_to_default")]
198    pub mfa_accounts: Vec<MfaAccount>,
199    pub need_update_password: bool,
200    pub ip_whitelist: String,
201}
202
203
204#[derive(Debug, Clone, Serialize, Deserialize, Default)]
205#[serde(rename_all = "camelCase", default)]
206pub struct FaceId {
207    pub name: String,
208    pub face_id_data: Vec<f64>,
209}
210
211
212#[derive(Debug, Clone, Serialize, Deserialize, Default)]
213#[serde(rename_all = "camelCase", default)]
214pub struct MfaProps {
215    pub enabled: bool,
216    pub is_preferred: bool,
217    pub mfa_type: String,
218    pub secret: Option<String>,
219    pub country_code: Option<String>,
220    pub url: Option<String>,
221    pub recovery_codes: Option<Vec<String>>,
222}
223
224
225#[derive(Debug, Clone, Serialize, Deserialize, Default)]
226#[serde(rename_all = "camelCase", default)]
227pub struct MfaAccount {
228    pub account_name: String,
229    pub issuer: String,
230    pub secret_key: String,
231}
232
233impl Model for User {
234    fn ident() -> &'static str {
235        "user"
236    }
237    fn plural_ident() -> &'static str {
238        "users"
239    }
240    fn support_update_columns() -> bool {
241        true
242    }
243    fn owner(&self) -> &str {
244        &self.owner
245    }
246    fn name(&self) -> &str {
247        &self.name
248    }
249}
250
251
252#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
253#[serde(rename_all = "camelCase", default)]
254pub struct UserGroup {
255    owner: String,
256    name: String,
257    created_time: String,
258    updated_time: String,
259
260    display_name: String,
261    manager: String,
262    contact_email: String,
263    type_: String,
264    parent_id: String,
265    is_top_group: bool,
266    users: Vec<String>,
267
268    title: Option<String>,
269    key: Option<String>,
270    children: Option<Vec<UserGroup>>,
271
272    is_enabled: bool,
273}
274
275impl Model for UserGroup {
276    fn ident() -> &'static str {
277        "group"
278    }
279    fn plural_ident() -> &'static str {
280        "groups"
281    }
282    fn owner(&self) -> &str {
283        &self.owner
284    }
285    fn name(&self) -> &str {
286        &self.name
287    }
288    fn support_update_columns() -> bool {
289        false
290    }
291}
292
293
294#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
295#[serde(rename_all = "camelCase", default)]
296pub struct ManagedAccount {
297    pub application: String,
298    pub password: String,
299    pub signin_url: String,
300    pub username: String,
301}
302
303
304#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
305#[serde(rename_all = "camelCase", default)]
306pub struct MultiFactorAuth {
307    pub country_code: String,
308    pub enabled: bool,
309    pub is_preferred: bool,
310    pub mfa_type: String,
311    #[serde(deserialize_with = "null_to_default")]
312    pub recovery_codes: Vec<String>,
313    pub secret: String,
314    pub url: String,
315}
316
317
318#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
319#[serde(rename_all = "camelCase", default)]
320pub struct WebauthnCredential {}
321
322/// The filter for query user.
323
324#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
325#[serde(rename_all = "camelCase")]
326pub enum QueryUserSet {
327    /// 0 for offline
328    Offline,
329    /// 1 for online
330    Online,
331    /// empty for all users
332    #[default]
333    #[serde(other)]
334    All,
335}
336impl Display for QueryUserSet {
337    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
338        match self {
339            QueryUserSet::Offline => write!(f, "0"),
340            QueryUserSet::Online => write!(f, "1"),
341            QueryUserSet::All => write!(f, ""),
342        }
343    }
344}
345
346#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
347pub struct UserQueryArgs {
348    #[serde(rename = "groupName", skip_serializing_if = "Option::is_none")]
349    pub group_name: Option<String>,
350    #[serde(rename = "pageSize", skip_serializing_if = "Option::is_none")]
351    pub page_size: Option<i32>,
352    /// page
353    #[serde(rename = "p", skip_serializing_if = "Option::is_none")]
354    pub page: Option<i32>,
355    #[serde(rename = "field", skip_serializing_if = "Option::is_none")]
356    pub field: Option<String>,
357    #[serde(rename = "value", skip_serializing_if = "Option::is_none")]
358    pub value: Option<String>,
359    #[serde(rename = "sortField", skip_serializing_if = "Option::is_none")]
360    pub sort_field: Option<String>,
361    #[serde(rename = "sortOrder", skip_serializing_if = "Option::is_none")]
362    pub sort_order: Option<String>,
363}
364impl IsQueryArgs for UserQueryArgs {}
365
366
367#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
368#[serde(rename_all = "camelCase")]
369pub struct GetUserArgs {
370    
371    #[serde(skip_serializing_if = "Option::is_none")]
372    pub user_id: Option<String>,
373    
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub name: Option<String>,
376    
377    #[serde(skip_serializing_if = "Option::is_none")]
378    pub email: Option<String>,
379    
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub phone: Option<String>,
382}
383
384
385#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
386pub struct UserGroupQueryArgs {
387    
388    #[serde(rename = "withTree", skip_serializing_if = "Option::is_none")]
389    pub with_tree: Option<String>,
390    
391    #[serde(rename = "pageSize", skip_serializing_if = "Option::is_none")]
392    pub page_size: Option<i32>,
393    /// page
394    
395    #[serde(rename = "p", skip_serializing_if = "Option::is_none")]
396    pub page: Option<i32>,
397    
398    #[serde(rename = "field", skip_serializing_if = "Option::is_none")]
399    pub field: Option<String>,
400    
401    #[serde(rename = "value", skip_serializing_if = "Option::is_none")]
402    pub value: Option<String>,
403    
404    #[serde(rename = "sortField", skip_serializing_if = "Option::is_none")]
405    pub sort_field: Option<String>,
406    
407    #[serde(rename = "sortOrder", skip_serializing_if = "Option::is_none")]
408    pub sort_order: Option<String>,
409}
410impl IsQueryArgs for UserGroupQueryArgs {}
411
412
413#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
414#[serde(rename_all = "camelCase")]
415pub struct SetPasswordArgs {
416    pub user_name: String,
417    pub new_password: String,
418    #[serde(skip_serializing_if = "Option::is_none")]
419    pub old_password: Option<String>,
420    #[serde(skip_serializing_if = "Option::is_none")]
421    pub user_owner: Option<String>,
422}
423
424#[cfg(test)]
425mod tests {
426    use super::*;
427    #[test]
428    fn test_user_query_args() {
429        let mut args = UserQueryArgs::default();
430        let query_part = serde_urlencoded::to_string(&args).unwrap();
431        assert_eq!("", query_part);
432
433        args.page = Some(0);
434        args.page_size = Some(1);
435        let query_part = serde_urlencoded::to_string(&args).unwrap();
436        assert_eq!("pageSize=1&p=0", query_part);
437    }
438    #[test]
439    fn test_user() {
440        let json_data = r#"
441    {
442        "owner": "example_owner",
443        "name": "example_name",
444        "createdTime": "2022-01-01T00:00:00Z",
445        "updatedTime": "2022-01-01T00:00:00Z",
446        
447        "id": "example_id",
448        "type": "example_type",
449        "password": "example_password",
450        "passwordSalt": "example_salt",
451        "passwordType": "example_type",
452        "displayName": "Example User",
453        "firstName": "First",
454        "lastName": "Last",
455        "avatar": "example_avatar",
456        "avatarType": "example_type",
457        "permanentAvatar": "example_perm_avatar",
458        "email": "example@example.com",
459        "emailVerified": true,
460        "phone": "123456789",
461        "countryCode": "example_cc",
462        "region": "example_region",
463        "location": "Example Location",
464        "address": ["Example Address"],
465        "affiliation": "example_affiliation",
466        "title": "example_title",
467        "idCardType": "example_card_type",
468        "idCard": "example_card",
469        "homepage": "https://example.com",
470        "bio": "Example bio",
471        "tag": "example_tag",
472        "language": "en",
473        "gender": "M",
474        "birthday": "1990-01-01",
475        "education": "example_education",
476        "score": 100,
477        "karma": 10,
478        "ranking": 1,
479        "isDefaultAvatar": true,
480        "isOnline": true,
481        "isAdmin": true,
482        "isForbidden": false,
483        "isDeleted": false,
484        "signupApplication": "example_signup_app",
485        "hash": "example_hash",
486        "preHash": "example_pre_hash",
487        
488        "github": "example_github",
489        "google": "example_google",
490        "qq": "example_qq",
491        "wechat": "example_wechat",
492        "facebook": "example_facebook",
493        "dingtalk": "example_dingtalk",
494        "weibo": "example_weibo",
495        "gitee": "example_gitee",
496        "linkedin": "example_linkedin",
497        "wecom": "example_wecom",
498        "lark": "example_lark",
499        "gitlab": "example_gitlab",
500        "ldap": "example_ldap",
501
502        "properties": {
503            "additionalProp1": "value1",
504            "additionalProp2": "value2",
505            "additionalProp3": "value3"
506        },
507        "groups": ["ExampleGroup"],
508        "lastSigninWrongTime": "2022-01-01T00:00:00Z",
509        "signinWrongTimes": 0
510    }
511    "#;
512
513        let casdoor_user: User = serde_json::from_str(json_data).expect("JSON parsing failed");
514        println!("{:?}", casdoor_user);
515    }
516}