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#[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#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
325#[serde(rename_all = "camelCase")]
326pub enum QueryUserSet {
327 Offline,
329 Online,
331 #[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 #[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 #[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}