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
14
pub async fn get_user(Extension(user): Extension<User>) -> impl IntoResponse {
45
14
    Json(response::GetUser {
46
14
        data: response::GetUserData {
47
14
            account: user.account.clone(),
48
14
            created_at: time_str(&user.created_at),
49
14
            modified_at: time_str(&user.modified_at),
50
14
            verified_at: match user.verified_at {
51
                None => None,
52
14
                Some(time) => Some(time_str(&time)),
53
            },
54
14
            roles: user.roles.clone(),
55
14
            name: user.name.clone(),
56
14
            info: user.info.clone(),
57
14
        },
58
14
    })
59
14
}
60

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

            
69
30
    let user_id = user.user_id.as_str();
70
30
    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
24
    }
75
24
    if updates.password.is_some() {
76
48
        remove_tokens(&FN_NAME, &state.model, user_id).await;
77
16
    }
78
24
    Ok(StatusCode::NO_CONTENT)
79
30
}
80

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

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

            
108
8
    let cond = QueryCond {
109
8
        account: Some(account.as_str()),
110
8
        ..Default::default()
111
8
    };
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
8
        Ok(user) => match user {
118
6
            None => (),
119
            Some(_) => {
120
2
                return Err(ErrResp::Custom(
121
2
                    ErrReq::USER_EXIST.0,
122
2
                    ErrReq::USER_EXIST.1,
123
2
                    None,
124
2
                ))
125
            }
126
        },
127
    }
128

            
129
6
    let now = Utc::now();
130
6
    let user_id = strings::random_id(&now, ID_RAND_LEN);
131
6
    let salt = strings::randomstring(SALT_LEN);
132
6
    let user = User {
133
6
        user_id: user_id.clone(),
134
6
        account,
135
6
        created_at: now,
136
6
        modified_at: now,
137
6
        verified_at: match body.expired_at {
138
4
            None => Some(now),
139
2
            Some(_) => None,
140
        },
141
6
        expired_at: body.expired_at,
142
6
        disabled_at: None,
143
6
        roles: HashMap::new(),
144
6
        password: strings::password_hash(body.data.password.as_str(), salt.as_str()),
145
6
        salt,
146
6
        name: match body.data.name.as_ref() {
147
2
            None => "".to_string(),
148
4
            Some(name) => name.clone(),
149
        },
150
6
        info: match body.data.info.as_ref() {
151
4
            None => Map::new(),
152
2
            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
6
    }
159
6
    Ok(Json(response::PostAdminUser {
160
6
        data: response::PostAdminUserData { user_id },
161
6
    }))
162
14
}
163

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

            
171
24
    let mut account_cond = None;
172
24
    let mut account_contains_cond = None;
173
24
    if let Some(account) = query.account.as_ref() {
174
16
        if account.len() > 0 {
175
8
            account_cond = Some(account.as_str());
176
8
        }
177
8
    }
178
24
    if account_cond.is_none() {
179
16
        if let Some(contains) = query.contains.as_ref() {
180
8
            if contains.len() > 0 {
181
8
                account_contains_cond = Some(contains.as_str());
182
8
            }
183
8
        }
184
8
    }
185
24
    let cond = ListQueryCond {
186
24
        account: account_cond,
187
24
        account_contains: account_contains_cond,
188
24
        ..Default::default()
189
24
    };
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
24
        Ok(count) => Ok(Json(response::GetAdminUserCount {
196
24
            data: response::GetCountData { count },
197
24
        })),
198
    }
199
24
}
200

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

            
208
78
    let mut account_cond = None;
209
78
    let mut account_contains_cond = None;
210
78
    if let Some(account) = query.account.as_ref() {
211
18
        if account.len() > 0 {
212
10
            account_cond = Some(account.as_str());
213
10
        }
214
60
    }
215
78
    if account_cond.is_none() {
216
68
        if let Some(contains) = query.contains.as_ref() {
217
46
            if contains.len() > 0 {
218
46
                account_contains_cond = Some(contains.as_str());
219
46
            }
220
22
        }
221
10
    }
222
78
    let cond = ListQueryCond {
223
78
        account: account_cond,
224
78
        account_contains: account_contains_cond,
225
78
        ..Default::default()
226
78
    };
227
78
    let fields_cond = get_list_fields(&query.fields);
228
78
    let sort_cond = get_sort_cond(&query.sort)?;
229
68
    let opts = ListOptions {
230
68
        cond: &cond,
231
68
        offset: query.offset,
232
68
        limit: match query.limit {
233
56
            None => Some(LIST_LIMIT_DEFAULT),
234
12
            Some(limit) => match limit {
235
6
                0 => None,
236
6
                _ => Some(limit),
237
            },
238
        },
239
68
        sort: Some(sort_cond.as_slice()),
240
68
        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
68
        Ok((list, cursor)) => match cursor {
249
2
            None => match query.format {
250
                Some(request::ListFormat::Array) => {
251
2
                    return Ok(Json(user_list_transform(&list, &fields_cond)).into_response())
252
                }
253
                _ => {
254
54
                    return Ok(Json(response::GetAdminUserList {
255
54
                        data: user_list_transform(&list, &fields_cond),
256
54
                    })
257
54
                    .into_response())
258
                }
259
            },
260
12
            Some(_) => (list, cursor),
261
12
        },
262
12
    };
263
12

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

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

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

            
326
6
    let cond = QueryCond {
327
6
        user_id: Some(param.user_id.as_str()),
328
6
        ..Default::default()
329
6
    };
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
6
        Ok(user) => match user {
336
2
            None => Err(ErrResp::ErrNotFound(None)),
337
4
            Some(user) => Ok(Json(response::GetAdminUser {
338
4
                data: user_transform(
339
4
                    &user,
340
4
                    &GetAdminFields {
341
4
                        ..Default::default()
342
4
                    },
343
4
                ),
344
4
            })),
345
        },
346
    }
347
6
}
348

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

            
358
34
    let cond = QueryCond {
359
34
        user_id: Some(param.user_id.as_str()),
360
34
        ..Default::default()
361
34
    };
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
34
        Ok(user) => match user {
368
2
            None => return Err(ErrResp::ErrNotFound(None)),
369
32
            Some(user) => user,
370
32
        },
371
32
    };
372
32

            
373
32
    let user_id = param.user_id.as_str();
374
32
    let updates = get_admin_updates(
375
32
        &body,
376
32
        Role::is_role(&user.roles, Role::ADMIN),
377
32
        &target_user,
378
32
        user.user_id.as_str(),
379
32
    )?;
380
27
    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
14
    }
384
14
    if updates.password.is_some() {
385
12
        remove_tokens(&FN_NAME, &state.model, user_id).await;
386
12
    }
387
14
    Ok(StatusCode::NO_CONTENT)
388
34
}
389

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

            
398
6
    if user.user_id == param.user_id {
399
2
        return Err(ErrResp::ErrPerm(Some("cannot delete oneself".to_string())));
400
4
    }
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
4
    }
405
4
    Ok(StatusCode::NO_CONTENT)
406
6
}
407

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

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

            
500
90
fn get_list_fields(fields_cond: &Option<String>) -> GetAdminFields {
501
90
    let mut ret_fields = GetAdminFields {
502
90
        expired: false,
503
90
        disabled: false,
504
90
    };
505
90
    if let Some(fields_args) = fields_cond {
506
16
        let mut fields = fields_args.split(",");
507
36
        while let Some(field) = fields.next() {
508
20
            match field {
509
20
                "expired" => ret_fields.expired = true,
510
12
                "disabled" => ret_fields.disabled = true,
511
4
                _ => (),
512
            }
513
        }
514
74
    }
515
90
    ret_fields
516
90
}
517

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

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

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

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

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

            
655
26
    if with_end {
656
12
        build_str += match format {
657
2
            Some(request::ListFormat::Array) => "]",
658
10
            _ => "]}",
659
        }
660
14
    }
661
26
    Ok(Bytes::copy_from_slice(build_str.as_str().as_bytes()))
662
26
}
663

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

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