casdoor_rs_sdk/user/
models.rs

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