tdm_server_rust/web/
manga_benefit_controller.rs1use crate::{
7 app::AppState,
8 common::result::ResultBody,
9 entity::manga::{MangaBenefitDto, VolumeVo},
10 error::{ApiResult, AppError},
11 service::manga_benefit_service::MangaBenefitService,
12};
13use axum::{
14 body::Bytes,
15 extract::{Multipart, Path, State},
16 routing::{get, post},
17 Router,
18};
19
20pub fn routes() -> Router<AppState> {
22 Router::new()
23 .route("/", post(add_manga_benefit).put(update_manga_benefit))
24 .route("/:id", get(get_manga_benefits).delete(delete_manga_benefit))
25}
26
27#[tracing::instrument(skip_all, level = "info")]
29pub async fn get_manga_benefits(
30 State(state): State<AppState>,
31 Path(manga_id): Path<i32>,
32) -> ApiResult<ResultBody<Vec<VolumeVo>>> {
33 let data = MangaBenefitService::get_manga_benefits_by_manga_id(&state, manga_id).await?;
34 Ok(ResultBody::success_data(data))
35}
36
37#[tracing::instrument(skip_all, level = "info")]
39pub async fn add_manga_benefit(
40 State(state): State<AppState>,
41 mut multipart: Multipart,
42) -> ApiResult<ResultBody<()>> {
43 let (file, dto) = parse_benefit_multipart(&mut multipart).await?;
44 MangaBenefitService::add_manga_benefit(&state, file, dto).await?;
45 Ok(ResultBody::success())
46}
47
48#[tracing::instrument(skip_all, level = "info")]
50pub async fn update_manga_benefit(
51 State(state): State<AppState>,
52 mut multipart: Multipart,
53) -> ApiResult<ResultBody<()>> {
54 let (file, dto) = parse_benefit_multipart(&mut multipart).await?;
55 MangaBenefitService::update_manga_benefit(&state, file, dto).await?;
56 Ok(ResultBody::success())
57}
58
59#[tracing::instrument(skip_all, level = "info")]
61pub async fn delete_manga_benefit(
62 State(state): State<AppState>,
63 Path(id): Path<i32>,
64) -> ApiResult<ResultBody<()>> {
65 MangaBenefitService::delete_manga_benefit_by_id(&state, id).await?;
66 Ok(ResultBody::success())
67}
68
69#[tracing::instrument(skip_all, level = "info")]
70async fn parse_benefit_multipart(
71 multipart: &mut Multipart,
72) -> ApiResult<(Option<Bytes>, MangaBenefitDto)> {
73 let mut file = None;
74 let mut dto = MangaBenefitDto {
75 id: None,
76 manga_id: 0,
77 volume_number: None,
78 volume_title: None,
79 store_name: None,
80 benefit_name: None,
81 benefit_tag: None,
82 img_url: None,
83 r#type: None,
84 publish_time: None,
85 };
86 while let Some(field) = multipart
87 .next_field()
88 .await
89 .map_err(|e| AppError::Internal(e.to_string()))?
90 {
91 match field.name() {
92 Some("file") => {
93 file = Some(
94 field
95 .bytes()
96 .await
97 .map_err(|e| AppError::Internal(e.to_string()))?,
98 );
99 }
100 Some("mangaBenefit") => {
101 let raw = field
102 .bytes()
103 .await
104 .map_err(|e| AppError::Internal(e.to_string()))?;
105 dto = serde_json::from_slice(&raw)
106 .map_err(|e| AppError::business(format!("mangaBenefit 解析失败: {e}")))?;
107 }
108 _ => {}
109 }
110 }
111 Ok((file, dto))
112}