1
use std::{collections::HashMap, error::Error as StdError, sync::Arc};
2

            
3
use axum::{
4
    Extension,
5
    body::{Body, Bytes},
6
    extract::State,
7
    http::{StatusCode, header},
8
    response::IntoResponse,
9
};
10
use chrono::{DateTime, Utc};
11
use log::{error, warn};
12
use serde_json::{self, Map, Value};
13

            
14
use sylvia_iot_corelib::{
15
    constants::ContentType,
16
    err::ErrResp,
17
    http::{Json, Path, Query},
18
    role::Role,
19
    strings::{self, time_str},
20
};
21

            
22
use super::{
23
    super::super::{ErrReq, State as AppState},
24
    request, response,
25
};
26
use crate::models::{
27
    Model, access_token, authorization_code, refresh_token,
28
    user::{ListOptions, ListQueryCond, QueryCond, SortCond, SortKey, Updates, User},
29
};
30

            
31
#[derive(Default)]
32
struct GetAdminFields {
33
    expired: bool,
34
    disabled: bool,
35
}
36

            
37
const LIST_LIMIT_DEFAULT: u64 = 100;
38
const LIST_CURSOR_MAX: u64 = 100;
39
const ID_RAND_LEN: usize = 8;
40
const SALT_LEN: usize = 8;
41

            
42
/// `GET /{base}/api/v1/user`
43
28
pub async fn get_user(Extension(user): Extension<User>) -> impl IntoResponse {
44
28
    Json(response::GetUser {
45
28
        data: response::GetUserData {
46
28
            account: user.account.clone(),
47
28
            created_at: time_str(&user.created_at),
48
28
            modified_at: time_str(&user.modified_at),
49
28
            verified_at: match user.verified_at {
50
                None => None,
51
28
                Some(time) => Some(time_str(&time)),
52
            },
53
28
            roles: user.roles.clone(),
54
28
            name: user.name.clone(),
55
28
            info: user.info.clone(),
56
28
        },
57
28
    })
58
28
}
59

            
60
/// `PATCH /{base}/api/v1/user`
61
60
pub async fn patch_user(
62
60
    State(state): State<AppState>,
63
60
    Extension(user): Extension<User>,
64
60
    Json(body): Json<request::PatchUserBody>,
65
60
) -> impl IntoResponse {
66
    const FN_NAME: &'static str = "patch_user";
67

            
68
60
    let user_id = user.user_id.as_str();
69
60
    let updates = get_updates(&body.data)?;
70
48
    if let Err(e) = state.model.user().update(user_id, &updates).await {
71
        error!("[{}] {}", FN_NAME, e);
72
        return Err(ErrResp::ErrDb(Some(e.to_string())));
73
48
    }
74
48
    if updates.password.is_some() {
75
16
        remove_tokens(&FN_NAME, &state.model, user_id).await;
76
32
    }
77
48
    Ok(StatusCode::NO_CONTENT)
78
60
}
79

            
80
/// `POST /{base}/api/v1/user`
81
28
pub async fn post_admin_user(
82
28
    State(state): State<AppState>,
83
28
    Json(body): Json<request::PostAdminUserBody>,
84
28
) -> impl IntoResponse {
85
    const FN_NAME: &'static str = "post_admin_user";
86

            
87
28
    let account = body.data.account.to_lowercase();
88
28
    if !strings::is_account(account.as_str()) {
89
4
        return Err(ErrResp::ErrParam(Some(
90
4
            "`account` must be email or [A-Za-z0-9]{1}[A-Za-z0-9-_]*".to_string(),
91
4
        )));
92
24
    } else if body.data.password.len() == 0 {
93
4
        return Err(ErrResp::ErrParam(Some(
94
4
            "`password` must at least one character".to_string(),
95
4
        )));
96
20
    }
97
20
    if let Some(info) = body.data.info.as_ref() {
98
8
        for (k, _) in info.iter() {
99
8
            if k.len() == 0 {
100
4
                return Err(ErrResp::ErrParam(Some(
101
4
                    "`info` key must not be empty".to_string(),
102
4
                )));
103
4
            }
104
        }
105
12
    }
106

            
107
16
    let cond = QueryCond {
108
16
        account: Some(account.as_str()),
109
16
        ..Default::default()
110
16
    };
111
16
    match state.model.user().get(&cond).await {
112
        Err(e) => {
113
            error!("[{}] get error: {}", FN_NAME, e);
114
            return Err(ErrResp::ErrDb(Some(e.to_string())));
115
        }
116
16
        Ok(user) => match user {
117
12
            None => (),
118
            Some(_) => {
119
4
                return Err(ErrResp::Custom(
120
4
                    ErrReq::USER_EXIST.0,
121
4
                    ErrReq::USER_EXIST.1,
122
4
                    None,
123
4
                ));
124
            }
125
        },
126
    }
127

            
128
12
    let now = Utc::now();
129
12
    let user_id = strings::random_id(&now, ID_RAND_LEN);
130
12
    let salt = strings::randomstring(SALT_LEN);
131
12
    let user = User {
132
12
        user_id: user_id.clone(),
133
12
        account,
134
12
        created_at: now,
135
12
        modified_at: now,
136
12
        verified_at: match body.expired_at {
137
8
            None => Some(now),
138
4
            Some(_) => None,
139
        },
140
12
        expired_at: body.expired_at,
141
12
        disabled_at: None,
142
12
        roles: HashMap::new(),
143
12
        password: strings::password_hash(body.data.password.as_str(), salt.as_str()),
144
12
        salt,
145
12
        name: match body.data.name.as_ref() {
146
4
            None => "".to_string(),
147
8
            Some(name) => name.clone(),
148
        },
149
12
        info: match body.data.info.as_ref() {
150
8
            None => Map::new(),
151
4
            Some(info) => info.clone(),
152
        },
153
    };
154
12
    if let Err(e) = state.model.user().add(&user).await {
155
        error!("[{}] add error: {}", FN_NAME, e);
156
        return Err(ErrResp::ErrDb(Some(e.to_string())));
157
12
    }
158
12
    Ok(Json(response::PostAdminUser {
159
12
        data: response::PostAdminUserData { user_id },
160
12
    }))
161
28
}
162

            
163
/// `GET /{base}/api/v1/user/count`
164
48
pub async fn get_admin_user_count(
165
48
    State(state): State<AppState>,
166
48
    Query(query): Query<request::GetAdminUserCountQuery>,
167
48
) -> impl IntoResponse {
168
    const FN_NAME: &'static str = "get_admin_user_count";
169

            
170
48
    let mut account_cond = None;
171
48
    let mut account_contains_cond = None;
172
48
    if let Some(account) = query.account.as_ref() {
173
32
        if account.len() > 0 {
174
16
            account_cond = Some(account.as_str());
175
16
        }
176
16
    }
177
48
    if account_cond.is_none() {
178
32
        if let Some(contains) = query.contains.as_ref() {
179
16
            if contains.len() > 0 {
180
16
                account_contains_cond = Some(contains.as_str());
181
16
            }
182
16
        }
183
16
    }
184
48
    let cond = ListQueryCond {
185
48
        account: account_cond,
186
48
        account_contains: account_contains_cond,
187
48
        ..Default::default()
188
48
    };
189
48
    match state.model.user().count(&cond).await {
190
        Err(e) => {
191
            error!("[{}] count error: {}", FN_NAME, e);
192
            Err(ErrResp::ErrDb(Some(e.to_string())))
193
        }
194
48
        Ok(count) => Ok(Json(response::GetAdminUserCount {
195
48
            data: response::GetCountData { count },
196
48
        })),
197
    }
198
48
}
199

            
200
/// `GET /{base}/api/v1/user/list`
201
156
pub async fn get_admin_user_list(
202
156
    State(state): State<AppState>,
203
156
    Query(query): Query<request::GetAdminUserListQuery>,
204
156
) -> impl IntoResponse {
205
    const FN_NAME: &'static str = "get_admin_user_list";
206

            
207
156
    let mut account_cond = None;
208
156
    let mut account_contains_cond = None;
209
156
    if let Some(account) = query.account.as_ref() {
210
36
        if account.len() > 0 {
211
20
            account_cond = Some(account.as_str());
212
20
        }
213
120
    }
214
156
    if account_cond.is_none() {
215
136
        if let Some(contains) = query.contains.as_ref() {
216
92
            if contains.len() > 0 {
217
92
                account_contains_cond = Some(contains.as_str());
218
92
            }
219
44
        }
220
20
    }
221
156
    let cond = ListQueryCond {
222
156
        account: account_cond,
223
156
        account_contains: account_contains_cond,
224
156
        ..Default::default()
225
156
    };
226
156
    let fields_cond = get_list_fields(&query.fields);
227
156
    let sort_cond = get_sort_cond(&query.sort)?;
228
136
    let opts = ListOptions {
229
136
        cond: &cond,
230
136
        offset: query.offset,
231
136
        limit: match query.limit {
232
112
            None => Some(LIST_LIMIT_DEFAULT),
233
24
            Some(limit) => match limit {
234
12
                0 => None,
235
12
                _ => Some(limit),
236
            },
237
        },
238
136
        sort: Some(sort_cond.as_slice()),
239
136
        cursor_max: Some(LIST_CURSOR_MAX),
240
    };
241

            
242
136
    let (list, cursor) = match state.model.user().list(&opts, None).await {
243
        Err(e) => {
244
            error!("[{}] list error: {}", FN_NAME, e);
245
            return Err(ErrResp::ErrDb(Some(e.to_string())));
246
        }
247
136
        Ok((list, cursor)) => match cursor {
248
4
            None => match query.format {
249
                Some(request::ListFormat::Array) => {
250
4
                    return Ok(Json(user_list_transform(&list, &fields_cond)).into_response());
251
                }
252
                _ => {
253
108
                    return Ok(Json(response::GetAdminUserList {
254
108
                        data: user_list_transform(&list, &fields_cond),
255
108
                    })
256
108
                    .into_response());
257
                }
258
            },
259
24
            Some(_) => (list, cursor),
260
24
        },
261
24
    };
262
24

            
263
24
    let body = Body::from_stream(async_stream::stream! {
264
24
        let mut account_cond = None;
265
24
        let mut account_contains_cond = None;
266
24
        if let Some(account) = query.account.as_ref() {
267
24
            if account.len() > 0 {
268
24
                account_cond = Some(account.as_str());
269
24
            }
270
24
        }
271
24
        if account_cond.is_none() {
272
24
            if let Some(contains) = query.contains.as_ref() {
273
24
                if contains.len() > 0 {
274
24
                    account_contains_cond = Some(contains.as_str());
275
24
                }
276
24
            }
277
24
        }
278
24
        let cond = ListQueryCond {
279
24
            account: account_cond,
280
24
            account_contains: account_contains_cond,
281
24
            ..Default::default()
282
24
        };
283
24
        let fields_cond = get_list_fields(&query.fields);
284
24
        let opts = ListOptions {
285
24
            cond: &cond,
286
24
            offset: query.offset,
287
24
            limit: match query.limit {
288
24
                None => Some(LIST_LIMIT_DEFAULT),
289
24
                Some(limit) => match limit {
290
24
                    0 => None,
291
24
                    _ => Some(limit),
292
24
                },
293
24
            },
294
24
            sort: Some(sort_cond.as_slice()),
295
24
            cursor_max: Some(LIST_CURSOR_MAX),
296
24
        };
297
24

            
298
24
        let mut list = list;
299
24
        let mut cursor = cursor;
300
24
        let mut is_first = true;
301
24
        loop {
302
24
            yield user_list_transform_bytes(&list, &fields_cond, is_first, cursor.is_none(), query.format.as_ref());
303
24
            is_first = false;
304
24
            if cursor.is_none() {
305
24
                break;
306
24
            }
307
24
            let (_list, _cursor) = match state.model.user().list(&opts, cursor).await {
308
24
                Err(_) => break,
309
24
                Ok((list, cursor)) => (list, cursor),
310
24
            };
311
24
            list = _list;
312
24
            cursor = _cursor;
313
24
        }
314
24
    });
315
24
    Ok(([(header::CONTENT_TYPE, ContentType::JSON)], body).into_response())
316
156
}
317

            
318
/// `GET /{base}/api/v1/user/{userId}`
319
12
pub async fn get_admin_user(
320
12
    State(state): State<AppState>,
321
12
    Path(param): Path<request::UserIdPath>,
322
12
) -> impl IntoResponse {
323
    const FN_NAME: &'static str = "get_admin_user";
324

            
325
12
    let cond = QueryCond {
326
12
        user_id: Some(param.user_id.as_str()),
327
12
        ..Default::default()
328
12
    };
329
12
    match state.model.user().get(&cond).await {
330
        Err(e) => {
331
            error!("[{}] get error: {}", FN_NAME, e);
332
            Err(ErrResp::ErrDb(Some(e.to_string())))
333
        }
334
12
        Ok(user) => match user {
335
4
            None => Err(ErrResp::ErrNotFound(None)),
336
8
            Some(user) => Ok(Json(response::GetAdminUser {
337
8
                data: user_transform(
338
8
                    &user,
339
8
                    &GetAdminFields {
340
8
                        ..Default::default()
341
8
                    },
342
8
                ),
343
8
            })),
344
        },
345
    }
346
12
}
347

            
348
/// `PATCH /{base}/api/v1/user/{userId}`
349
68
pub async fn patch_admin_user(
350
68
    State(state): State<AppState>,
351
68
    Extension(user): Extension<User>,
352
68
    Path(param): Path<request::UserIdPath>,
353
68
    Json(body): Json<request::PatchAdminUserBody>,
354
68
) -> impl IntoResponse {
355
    const FN_NAME: &'static str = "patch_admin_user";
356

            
357
68
    let cond = QueryCond {
358
68
        user_id: Some(param.user_id.as_str()),
359
68
        ..Default::default()
360
68
    };
361
68
    let target_user = match state.model.user().get(&cond).await {
362
        Err(e) => {
363
            error!("[{}] get error: {}", FN_NAME, e);
364
            return Err(ErrResp::ErrDb(Some(e.to_string())));
365
        }
366
68
        Ok(user) => match user {
367
4
            None => return Err(ErrResp::ErrNotFound(None)),
368
64
            Some(user) => user,
369
64
        },
370
64
    };
371
64

            
372
64
    let user_id = param.user_id.as_str();
373
64
    let updates = get_admin_updates(
374
64
        &body,
375
64
        Role::is_role(&user.roles, Role::ADMIN),
376
64
        &target_user,
377
64
        user.user_id.as_str(),
378
64
    )?;
379
28
    if let Err(e) = state.model.user().update(user_id, &updates).await {
380
        error!("[{}] update error: {}", FN_NAME, e);
381
        return Err(ErrResp::ErrDb(Some(e.to_string())));
382
28
    }
383
28
    if updates.password.is_some() {
384
4
        remove_tokens(&FN_NAME, &state.model, user_id).await;
385
24
    }
386
28
    Ok(StatusCode::NO_CONTENT)
387
68
}
388

            
389
/// `DELETE /{base}/api/v1/user/{userId}`
390
12
pub async fn delete_admin_user(
391
12
    State(state): State<AppState>,
392
12
    Extension(user): Extension<User>,
393
12
    Path(param): Path<request::UserIdPath>,
394
12
) -> impl IntoResponse {
395
    const FN_NAME: &'static str = "delete_admin_user";
396

            
397
12
    if user.user_id == param.user_id {
398
4
        return Err(ErrResp::ErrPerm(Some("cannot delete oneself".to_string())));
399
8
    }
400
8
    if let Err(e) = state.model.user().del(param.user_id.as_str()).await {
401
        error!("[{}] del error: {}", FN_NAME, e);
402
        return Err(ErrResp::ErrDb(Some(e.to_string())));
403
8
    }
404
8
    Ok(StatusCode::NO_CONTENT)
405
12
}
406

            
407
60
fn get_updates(body: &request::PatchUserData) -> Result<Updates, ErrResp> {
408
60
    let mut updates = Updates {
409
60
        ..Default::default()
410
60
    };
411
60
    let mut count = 0;
412
60
    if let Some(password) = body.password.as_ref() {
413
20
        if password.len() == 0 {
414
4
            return Err(ErrResp::ErrParam(Some(
415
4
                "`password` must at least one character".to_string(),
416
4
            )));
417
16
        }
418
16
        let salt = strings::randomstring(SALT_LEN);
419
16
        updates.password = Some(strings::password_hash(password, salt.as_str()));
420
16
        updates.salt = Some(salt);
421
16
        count += 1;
422
40
    }
423
56
    if let Some(name) = body.name.as_ref() {
424
48
        updates.name = Some(name.as_str());
425
48
        count += 1;
426
48
    }
427
56
    if let Some(info) = body.info.as_ref() {
428
52
        for (k, _) in info.iter() {
429
52
            if k.len() == 0 {
430
4
                return Err(ErrResp::ErrParam(Some(
431
4
                    "`info` key must not be empty".to_string(),
432
4
                )));
433
48
            }
434
        }
435
48
        updates.info = Some(info);
436
48
        count += 1;
437
4
    }
438
52
    if count == 0 {
439
4
        return Err(ErrResp::ErrParam(Some(
440
4
            "at least one parameter".to_string(),
441
4
        )));
442
48
    }
443
48
    updates.modified_at = Some(Utc::now());
444
48
    Ok(updates)
445
60
}
446

            
447
156
fn get_sort_cond(sort_args: &Option<String>) -> Result<Vec<SortCond>, ErrResp> {
448
156
    match sort_args.as_ref() {
449
96
        None => Ok(vec![SortCond {
450
96
            key: SortKey::Account,
451
96
            asc: true,
452
96
        }]),
453
60
        Some(args) => {
454
60
            let mut args = args.split(",");
455
60
            let mut sort_cond = vec![];
456
120
            while let Some(arg) = args.next() {
457
80
                let mut cond = arg.split(":");
458
80
                let key = match cond.next() {
459
                    None => return Err(ErrResp::ErrParam(Some("wrong sort argument".to_string()))),
460
80
                    Some(field) => match field {
461
80
                        "account" => SortKey::Account,
462
56
                        "created" => SortKey::CreatedAt,
463
36
                        "modified" => SortKey::ModifiedAt,
464
28
                        "verified" => SortKey::VerifiedAt,
465
20
                        "name" => SortKey::Name,
466
                        _ => {
467
8
                            return Err(ErrResp::ErrParam(Some(format!(
468
8
                                "invalid sort key {}",
469
8
                                field
470
8
                            ))));
471
                        }
472
                    },
473
                };
474
72
                let asc = match cond.next() {
475
4
                    None => return Err(ErrResp::ErrParam(Some("wrong sort argument".to_string()))),
476
68
                    Some(asc) => match asc {
477
68
                        "asc" => true,
478
24
                        "desc" => false,
479
                        _ => {
480
4
                            return Err(ErrResp::ErrParam(Some(format!(
481
4
                                "invalid sort asc {}",
482
4
                                asc
483
4
                            ))));
484
                        }
485
                    },
486
                };
487
64
                if cond.next().is_some() {
488
4
                    return Err(ErrResp::ErrParam(Some(
489
4
                        "invalid sort condition".to_string(),
490
4
                    )));
491
60
                }
492
60
                sort_cond.push(SortCond { key, asc });
493
            }
494
40
            Ok(sort_cond)
495
        }
496
    }
497
156
}
498

            
499
180
fn get_list_fields(fields_cond: &Option<String>) -> GetAdminFields {
500
180
    let mut ret_fields = GetAdminFields {
501
180
        expired: false,
502
180
        disabled: false,
503
180
    };
504
180
    if let Some(fields_args) = fields_cond {
505
32
        let mut fields = fields_args.split(",");
506
72
        while let Some(field) = fields.next() {
507
40
            match field {
508
40
                "expired" => ret_fields.expired = true,
509
24
                "disabled" => ret_fields.disabled = true,
510
8
                _ => (),
511
            }
512
        }
513
148
    }
514
180
    ret_fields
515
180
}
516

            
517
64
fn get_admin_updates<'a>(
518
64
    body: &'a request::PatchAdminUserBody,
519
64
    is_admin: bool,
520
64
    target_user: &User,
521
64
    op_user_id: &str,
522
64
) -> Result<Updates<'a>, ErrResp> {
523
64
    if !is_admin && Role::is_role(&target_user.roles, Role::ADMIN) {
524
8
        warn!("{} try to patch admin", op_user_id);
525
8
        return Err(ErrResp::ErrPerm(None));
526
56
    }
527
56

            
528
56
    let mut updates = Updates {
529
56
        ..Default::default()
530
56
    };
531
56
    let mut count = 0;
532
56
    if let Some(data) = body.data.as_ref() {
533
40
        if let Some(verified_at) = data.verified_at.as_ref() {
534
12
            if is_admin {
535
12
                updates.verified_at = match DateTime::parse_from_rfc3339(verified_at.as_str()) {
536
4
                    Err(e) => {
537
4
                        return Err(ErrResp::ErrParam(Some(format!(
538
4
                            "wrong `verified_at`: {}",
539
4
                            e
540
4
                        ))));
541
                    }
542
8
                    Ok(time) => Some(time.into()),
543
8
                };
544
8
                updates.expired_at = Some(None);
545
8
                count += 1;
546
            }
547
28
        }
548
36
        if let Some(roles) = data.roles.as_ref() {
549
24
            if !is_admin {
550
16
                if Role::is_role(roles, Role::ADMIN) || Role::is_role(roles, Role::SERVICE) {
551
8
                    warn!("{} try to patch user to role admin/service", op_user_id);
552
8
                    return Err(ErrResp::ErrPerm(None));
553
8
                }
554
8
            }
555
16
            updates.roles = Some(roles);
556
16
            count += 1;
557
12
        }
558
28
        if let Some(password) = data.password.as_ref() {
559
8
            if is_admin {
560
8
                if password.len() == 0 {
561
4
                    return Err(ErrResp::ErrParam(Some(
562
4
                        "`password` must at least one character".to_string(),
563
4
                    )));
564
4
                }
565
4
                let salt = strings::randomstring(SALT_LEN);
566
4
                updates.password = Some(strings::password_hash(password, salt.as_str()));
567
4
                updates.salt = Some(salt);
568
4
                count += 1;
569
            }
570
20
        }
571
24
        if let Some(name) = data.name.as_ref() {
572
8
            if is_admin {
573
8
                updates.name = Some(name.as_str());
574
8
                count += 1;
575
8
            }
576
16
        }
577
24
        if let Some(info) = data.info.as_ref() {
578
12
            if is_admin {
579
12
                for (k, _) in info.iter() {
580
12
                    if k.len() == 0 {
581
4
                        return Err(ErrResp::ErrParam(Some(
582
4
                            "`info` key must not be empty".to_string(),
583
4
                        )));
584
8
                    }
585
                }
586
8
                updates.info = Some(info);
587
8
                count += 1;
588
            }
589
12
        }
590
16
    }
591
36
    if let Some(disable) = body.disable.as_ref() {
592
28
        if !is_admin
593
12
            && (Role::is_role(&target_user.roles, Role::ADMIN)
594
12
                || Role::is_role(&target_user.roles, Role::MANAGER))
595
        {
596
4
            warn!("{} try to disable admin/manager", op_user_id);
597
4
            return Err(ErrResp::ErrPerm(None));
598
24
        }
599
24
        updates.disabled_at = match disable {
600
12
            false => Some(None),
601
12
            true => Some(Some(Utc::now())),
602
        };
603
24
        count += 1;
604
8
    }
605
32
    if count == 0 {
606
4
        return Err(ErrResp::ErrParam(Some(
607
4
            "at least one parameter".to_string(),
608
4
        )));
609
28
    }
610
28
    updates.modified_at = Some(Utc::now());
611
28
    Ok(updates)
612
64
}
613

            
614
112
fn user_list_transform(
615
112
    list: &Vec<User>,
616
112
    fields_cond: &GetAdminFields,
617
112
) -> Vec<response::GetAdminUserData> {
618
112
    let mut ret = vec![];
619
472
    for user in list.iter() {
620
472
        ret.push(user_transform(&user, fields_cond));
621
472
    }
622
112
    ret
623
112
}
624

            
625
52
fn user_list_transform_bytes(
626
52
    list: &Vec<User>,
627
52
    fields_cond: &GetAdminFields,
628
52
    with_start: bool,
629
52
    with_end: bool,
630
52
    format: Option<&request::ListFormat>,
631
52
) -> Result<Bytes, Box<dyn StdError + Send + Sync>> {
632
52
    let mut build_str = match with_start {
633
28
        false => "".to_string(),
634
4
        true => match format {
635
4
            Some(request::ListFormat::Array) => "[".to_string(),
636
20
            _ => "{\"data\":[".to_string(),
637
        },
638
    };
639
52
    let mut is_first = with_start;
640

            
641
3656
    for item in list {
642
3604
        if is_first {
643
24
            is_first = false;
644
3580
        } else {
645
3580
            build_str.push(',');
646
3580
        }
647
3604
        let json_str = match serde_json::to_string(&user_transform(item, fields_cond)) {
648
            Err(e) => return Err(Box::new(e)),
649
3604
            Ok(str) => str,
650
3604
        };
651
3604
        build_str += json_str.as_str();
652
    }
653

            
654
52
    if with_end {
655
24
        build_str += match format {
656
4
            Some(request::ListFormat::Array) => "]",
657
20
            _ => "]}",
658
        }
659
28
    }
660
52
    Ok(Bytes::copy_from_slice(build_str.as_str().as_bytes()))
661
52
}
662

            
663
4084
fn user_transform(user: &User, fields_cond: &GetAdminFields) -> response::GetAdminUserData {
664
4084
    response::GetAdminUserData {
665
4084
        user_id: user.user_id.clone(),
666
4084
        account: user.account.clone(),
667
4084
        created_at: time_str(&user.created_at),
668
4084
        modified_at: time_str(&user.modified_at),
669
4084
        verified_at: match user.verified_at.as_ref() {
670
168
            None => None,
671
3916
            Some(value) => Some(time_str(value)),
672
        },
673
4084
        expired_at: match fields_cond.expired {
674
3996
            false => None,
675
88
            true => match user.expired_at.as_ref() {
676
56
                None => Some(Value::Null),
677
32
                Some(value) => Some(Value::String(time_str(value))),
678
            },
679
        },
680
4084
        disabled_at: match fields_cond.disabled {
681
3980
            false => None,
682
104
            true => match user.disabled_at.as_ref() {
683
88
                None => Some(Value::Null),
684
16
                Some(value) => Some(Value::String(time_str(value))),
685
            },
686
        },
687
4084
        roles: user.roles.clone(),
688
4084
        name: user.name.clone(),
689
4084
        info: user.info.clone(),
690
4084
    }
691
4084
}
692

            
693
20
async fn remove_tokens(fn_name: &str, model: &Arc<dyn Model>, user_id: &str) {
694
20
    let cond = authorization_code::QueryCond {
695
20
        user_id: Some(user_id),
696
20
        ..Default::default()
697
20
    };
698
20
    if let Err(e) = model.authorization_code().del(&cond).await {
699
        error!("[{}] delete access token error: {}", fn_name, e);
700
20
    }
701
20
    let cond = access_token::QueryCond {
702
20
        user_id: Some(user_id),
703
20
        ..Default::default()
704
20
    };
705
20
    if let Err(e) = model.access_token().del(&cond).await {
706
        error!("[{}] delete access token error: {}", fn_name, e);
707
20
    }
708
20
    let cond = refresh_token::QueryCond {
709
20
        user_id: Some(user_id),
710
20
        ..Default::default()
711
20
    };
712
20
    if let Err(e) = model.refresh_token().del(&cond).await {
713
        error!("[{}] delete refresh token error: {}", fn_name, e);
714
20
    }
715
20
}