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

            
3
use axum::{
4
    body::{Body, Bytes},
5
    extract::State,
6
    http::{header, StatusCode},
7
    response::IntoResponse,
8
    Extension,
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
    access_token, authorization_code, refresh_token,
28
    user::{ListOptions, ListQueryCond, QueryCond, SortCond, SortKey, Updates, User},
29
    Model,
30
};
31

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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