1use crate::utils::query_deserialize::{
7 de_opt_i16, de_opt_i32, de_opt_string, de_page, de_page_size,
8};
9use crate::{
10 app::AppState,
11 common::result::{json_bytes_response, ResultBody},
12 common::AppJson,
13 entity::member::{
14 MemberAddRequest, MemberEpisode, MemberInfoVo, MemberSelfUpdateRequest,
15 MemberUpdateRequest, ResetPassword,
16 },
17 error::{ApiResult, AppError},
18 middleware::AuthMember,
19 service::member_service::MemberService,
20};
21use axum::{
22 extract::{Extension, Path, Query, State},
23 response::Response,
24 routing::{get, patch, put},
25 Router,
26};
27use serde::Deserialize;
28
29#[derive(Debug, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct MemberPageQuery {
33 #[serde(default, deserialize_with = "de_page")]
35 pub page: i32,
36 #[serde(default, deserialize_with = "de_page_size")]
38 pub page_size: i32,
39 #[serde(default, deserialize_with = "de_opt_string")]
41 pub username: Option<String>,
42 #[serde(default, deserialize_with = "de_opt_i16")]
44 pub post: Option<i16>,
45 #[serde(default, deserialize_with = "de_opt_i16")]
47 pub intern: Option<i16>,
48 #[serde(default, deserialize_with = "de_opt_string")]
50 pub email: Option<String>,
51}
52
53#[derive(Debug, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct MemberEpisodePageQuery {
57 #[serde(default, deserialize_with = "de_page")]
59 pub page: i32,
60 #[serde(default, deserialize_with = "de_page_size")]
62 pub page_size: i32,
63 #[serde(default, deserialize_with = "de_opt_i32")]
65 pub id: Option<i32>,
66}
67
68#[derive(Debug, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub struct MemberWorkbenchTasksQuery {
72 #[serde(default, deserialize_with = "de_page")]
74 pub page: i32,
75 #[serde(default, deserialize_with = "de_page_size")]
77 pub page_size: i32,
78 #[serde(default, deserialize_with = "de_opt_string")]
80 pub tab: Option<String>,
81 #[serde(default, deserialize_with = "de_opt_string")]
83 pub view: Option<String>,
84 #[serde(default, deserialize_with = "de_opt_string")]
86 pub keyword: Option<String>,
87}
88
89pub fn routes() -> Router<AppState> {
91 Router::new()
92 .route("/", get(page_member).post(new_member).put(update_member))
93 .route("/all", get(get_member_list))
94 .route("/self", put(update_member_self))
95 .route("/updatepwd", patch(update_member_password))
96 .route("/memberepisode", get(page_episode))
97 .route("/workbench/:id/overview", get(workbench_overview))
98 .route("/workbench/:id/tasks", get(workbench_tasks))
99 .route("/takeEpisode", patch(take_episode))
100 .route("/submitEpisode", patch(submit_episode))
101 .route("/stationedMangas/:id", get(find_stationed_mangas))
102 .route("/:id", get(get_member_by_id).delete(delete_member))
103}
104
105#[tracing::instrument(skip_all, level = "info")]
107pub async fn page_member(
108 State(state): State<AppState>,
109 Query(q): Query<MemberPageQuery>,
110) -> ApiResult<Response> {
111 let json = MemberService::page_json(
112 &state,
113 q.page,
114 q.page_size,
115 q.username,
116 q.post,
117 q.intern,
118 q.email,
119 )
120 .await?;
121 Ok(json_bytes_response(json))
122}
123
124#[tracing::instrument(skip_all, level = "info")]
126pub async fn get_member_list(State(state): State<AppState>) -> ApiResult<Response> {
127 let json = MemberService::get_member_list_json(&state).await?;
128 Ok(json_bytes_response(json))
129}
130
131#[tracing::instrument(skip_all, level = "info")]
133pub async fn delete_member(
134 State(state): State<AppState>,
135 Path(id): Path<String>,
136) -> ApiResult<ResultBody<()>> {
137 let id_list: Vec<i32> = id
138 .split(',')
139 .filter_map(|s| s.trim().parse().ok())
140 .collect();
141 MemberService::delete(&state, id_list).await?;
142 Ok(ResultBody::success())
143}
144
145#[tracing::instrument(skip_all, level = "info")]
147pub async fn new_member(
148 State(state): State<AppState>,
149 AppJson(body): AppJson<MemberAddRequest>,
150) -> ApiResult<ResultBody<()>> {
151 MemberService::new_member(&state, body).await?;
152 Ok(ResultBody::success())
153}
154
155#[tracing::instrument(skip_all, level = "info")]
157pub async fn get_member_by_id(
158 State(state): State<AppState>,
159 Path(id): Path<String>,
160) -> ApiResult<ResultBody<MemberInfoVo>> {
161 let id: i32 = id
162 .parse()
163 .map_err(|_| crate::error::AppError::business("无效的组员 ID 喵"))?;
164 let m = MemberService::get_member_by_id(&state, id).await?;
165 Ok(ResultBody::success_data(MemberInfoVo::from(m)))
166}
167
168#[tracing::instrument(skip_all, level = "info")]
170pub async fn update_member(
171 State(state): State<AppState>,
172 AppJson(body): AppJson<MemberUpdateRequest>,
173) -> ApiResult<ResultBody<()>> {
174 MemberService::update_member(&state, body).await?;
175 Ok(ResultBody::success())
176}
177
178#[tracing::instrument(skip_all, level = "info")]
180pub async fn update_member_self(
181 State(state): State<AppState>,
182 AppJson(body): AppJson<MemberSelfUpdateRequest>,
183) -> ApiResult<ResultBody<()>> {
184 MemberService::update_member_self(&state, body).await?;
185 Ok(ResultBody::success())
186}
187
188#[tracing::instrument(skip_all, level = "info")]
190pub async fn find_stationed_mangas(
191 State(state): State<AppState>,
192 Path(id): Path<String>,
193) -> ApiResult<Response> {
194 let id: i32 = id
195 .parse()
196 .map_err(|_| AppError::business("无效的组员 ID 喵"))?;
197 let json = MemberService::find_stationed_mangas_json(&state, id).await?;
198 Ok(json_bytes_response(json))
199}
200
201#[tracing::instrument(skip_all, level = "info")]
203pub async fn update_member_password(
204 State(state): State<AppState>,
205 AppJson(body): AppJson<ResetPassword>,
206) -> ApiResult<ResultBody<()>> {
207 MemberService::update_member_password(&state, body).await?;
208 Ok(ResultBody::success())
209}
210
211#[tracing::instrument(skip_all, level = "info")]
213pub async fn page_episode(
214 State(state): State<AppState>,
215 Query(q): Query<MemberEpisodePageQuery>,
216) -> ApiResult<Response> {
217 let id = q.id.ok_or_else(|| AppError::business("无效的组员 ID 喵"))?;
218 let json = MemberService::page_episode_json(&state, q.page, q.page_size, id).await?;
219 Ok(json_bytes_response(json))
220}
221
222#[tracing::instrument(skip_all, level = "info")]
224pub async fn workbench_overview(
225 State(state): State<AppState>,
226 Path(id): Path<String>,
227) -> ApiResult<Response> {
228 let id: i32 = id
229 .parse()
230 .map_err(|_| AppError::business("无效的组员 ID 喵"))?;
231 let json = MemberService::get_workbench_overview_json(&state, id).await?;
232 Ok(json_bytes_response(json))
233}
234
235#[tracing::instrument(skip_all, level = "info")]
237pub async fn workbench_tasks(
238 State(state): State<AppState>,
239 Path(id): Path<String>,
240 Query(q): Query<MemberWorkbenchTasksQuery>,
241) -> ApiResult<Response> {
242 let id: i32 = id
243 .parse()
244 .map_err(|_| AppError::business("无效的组员 ID 喵"))?;
245 let json = MemberService::page_workbench_tasks_json(
246 &state,
247 id,
248 q.tab.as_deref(),
249 q.view.as_deref(),
250 q.keyword.as_deref(),
251 q.page,
252 q.page_size,
253 )
254 .await?;
255 Ok(json_bytes_response(json))
256}
257
258#[tracing::instrument(skip_all, level = "info")]
260pub async fn take_episode(
261 State(state): State<AppState>,
262 Extension(AuthMember(member)): Extension<AuthMember>,
263 AppJson(body): AppJson<MemberEpisode>,
264) -> ApiResult<ResultBody<()>> {
265 MemberService::take_episode(&state, body, member).await?;
266 Ok(ResultBody::success())
267}
268
269#[tracing::instrument(skip_all, level = "info")]
271pub async fn submit_episode(
272 State(state): State<AppState>,
273 Extension(AuthMember(_member)): Extension<AuthMember>,
274 AppJson(body): AppJson<MemberEpisode>,
275) -> ApiResult<ResultBody<()>> {
276 MemberService::submit_episode(&state, body).await?;
277 Ok(ResultBody::success())
278}