daoyi_cloud_common/common_test_routers_example/
user.rs

1use rbatis::impl_select_page;
2use rbatis::plugin::page::PageRequest;
3use askama::Template;
4use salvo::oapi::extract::*;
5use salvo::prelude::*;
6use serde::{Deserialize, Serialize};
7use ulid::Ulid;
8use validator::Validate;
9use crate::common_hoops::jwt;
10
11use crate::models::{SafeUser, User};
12use crate::{db, empty_ok, json_ok, utils, AppResult, EmptyResult, JsonResult};
13
14#[derive(Template)]
15#[template(path = "user_list_page.html")]
16pub struct UserListPageTemplate {}
17
18#[derive(Template)]
19#[template(path = "user_list_frag.html")]
20pub struct UserListFragTemplate {}
21
22#[handler]
23pub async fn list_page(req: &mut Request, res: &mut Response) -> AppResult<()> {
24    let is_fragment = req.headers().get("X-Fragment-Header");
25    if let Some(cookie) = res.cookies().get("jwt_token") {
26        let token = cookie.value().to_string();
27        if !jwt::decode_token(&token) {
28            res.render(Redirect::other("/login"));
29        }
30    }
31    match is_fragment {
32        Some(_) => {
33            let hello_tmpl = UserListFragTemplate {};
34            res.render(Text::Html(hello_tmpl.render().unwrap()));
35        }
36        None => {
37            let hello_tmpl = UserListPageTemplate {};
38            res.render(Text::Html(hello_tmpl.render().unwrap()));
39        }
40    }
41    Ok(())
42}
43
44#[derive(Deserialize, Debug, Validate, ToSchema, Default)]
45pub struct CreateInData {
46    #[validate(length(min = 5, message = "username length must be greater than 5"))]
47    pub username: String,
48    #[validate(length(min = 6, message = "password length must be greater than 5"))]
49    pub password: String,
50}
51
52#[endpoint(tags("users"))]
53pub async fn create_user(idata: JsonBody<CreateInData>) -> JsonResult<SafeUser> {
54    let CreateInData { username, password } = idata.into_inner();
55    let rb = db::engine();
56
57    let id = Ulid::new().to_string();
58    let user = User {
59        id: id.clone(),
60        username: username.clone(),
61        password: utils::hash_password(&password)?,
62    };
63
64    User::insert(rb, &user).await.map_err(anyhow::Error::from)?;
65
66    json_ok(SafeUser {
67        id: id,
68        username: username,
69    })
70}
71
72#[derive(Deserialize, Debug, Validate, ToSchema)]
73struct UpdateInData {
74    #[validate(length(min = 5, message = "username length must be greater than 5"))]
75    username: String,
76    #[validate(length(min = 6, message = "password length must be greater than 5"))]
77    password: String,
78}
79#[endpoint(tags("users"), parameters(("user_id", description = "user id")))]
80pub async fn update_user(
81    user_id: PathParam<String>,
82    idata: JsonBody<UpdateInData>,
83) -> JsonResult<SafeUser> {
84    let user_id = user_id.into_inner();
85    let idata = idata.into_inner();
86    let rb = db::engine();
87
88    let user = User {
89        id: user_id.clone(),
90        username: idata.username.clone(),
91        password: utils::hash_password(&idata.password)?,
92    };
93
94    User::update_by_column(rb, &user, "id")
95        .await
96        .map_err(anyhow::Error::from)?;
97
98    json_ok(SafeUser {
99        id: user_id,
100        username: idata.username,
101    })
102}
103
104#[endpoint(tags("users"))]
105pub async fn delete_user(user_id: PathParam<String>) -> EmptyResult {
106    let rb = db::engine();
107    User::delete_by_column(rb, "id", &user_id.into_inner())
108        .await
109        .map_err(anyhow::Error::from)?;
110    empty_ok()
111}
112
113impl_select_page!(User{select_page() =>"
114     if !sql.contains('count(1)'):
115       `order by id desc`"},"users");
116
117impl_select_page!(User{select_page_by_username(username:&str) =>"
118     if username != null && username != '':
119       `where username like #{username}`"},"users");
120
121#[derive(Debug, Deserialize, Validate, Extractible, ToSchema)]
122#[salvo(extract(default_source(from = "query")))]
123pub struct UserListQuery {
124    pub username: Option<String>,
125    #[serde(default = "default_page")]
126    pub current_page: u64,
127    #[serde(default = "default_page_size")]
128    pub page_size: u64,
129}
130
131fn default_page() -> u64 {
132    1
133}
134fn default_page_size() -> u64 {
135    10
136}
137
138#[derive(Debug, Serialize, ToSchema)]
139pub struct UserListResponse {
140    pub data: Vec<SafeUser>,
141    pub total: i64,
142    pub current_page: u64,
143    pub page_size: u64,
144}
145
146#[endpoint(tags("users"), status_codes(200, 400))]
147pub async fn list_users(query: &mut Request) -> JsonResult<UserListResponse> {
148    let rb = db::engine();
149    let query: UserListQuery = query.extract().await?;
150
151    let page_req = PageRequest::new(query.current_page, query.page_size);
152
153    let page = if let Some(username) = query.username {
154        let pattern = format!("%{}%", username);
155        User::select_page_by_username(rb, &page_req, &pattern)
156            .await
157            .map_err(anyhow::Error::from)?
158    } else {
159        User::select_page(rb, &page_req)
160            .await
161            .map_err(anyhow::Error::from)?
162    };
163
164    let safe_users: Vec<SafeUser> = page
165        .records
166        .into_iter()
167        .map(|user| SafeUser {
168            id: user.id,
169            username: user.username,
170        })
171        .collect();
172
173    json_ok(UserListResponse {
174        data: safe_users,
175        total: page.total as i64,
176        current_page: query.current_page,
177        page_size: query.page_size,
178    })
179}