daoyi_cloud_common/common_test_routers_example/
user.rs1use 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}