feat: tag api

This commit is contained in:
brian
2025-06-22 18:27:54 +08:00
parent 6834c66974
commit cade85d576
5 changed files with 189 additions and 2 deletions

View File

@@ -1,2 +1,3 @@
pub mod book; pub mod book;
pub mod category; pub mod category;
pub mod tag;

170
src/api/tag.rs Normal file
View File

@@ -0,0 +1,170 @@
use axum::routing::{get, post};
use axum::{
extract::{Path, State},
http::StatusCode,
Json, Router,
};
use axum_macros::debug_handler;
use crate::middleware::auth::Claims;
use crate::model::db::tag::ActiveModel as TagActiveModel;
use crate::model::db::tag::Column as TagColumn;
use crate::model::db::tag::Model as TagModel;
use crate::model::db::prelude::Tag;
use crate::model::http_body::tag::{TagInfo, TagItem};
use crate::model::http_body::common::SimpleResponse;
use crate::AppState;
use sea_orm::sqlx::types::chrono::Local;
use sea_orm::{entity::*, query::*};
use sea_orm::{ColumnTrait};
pub fn get_nest_handlers() -> Router<crate::AppState> {
Router::new()
.route("/{id}/update",post(update_tag))
.route("/{id}",get(get_tag_by_id))
.route("/", post(create_tag).get(get_all_tags))
}
// handlers
//
#[debug_handler]
async fn get_all_tags(
state: State<AppState>,
claims: Claims,
) -> Result<Json<Vec<TagItem>>, (StatusCode, String)> {
let uid: i64 = claims.uid.clone();
let all_tags = Tag::find()
.filter(TagColumn::Uid.eq(uid))
.all(&state.conn)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let mut tags: Vec<TagItem> = Vec::new();
for b in all_tags {
let tag_resp = TagItem {
id: b.id.into(),
name: b.name,
};
tags.push(tag_resp);
}
Ok(Json(tags))
}
#[debug_handler]
async fn get_tag_by_id(
Path(id): Path<i64>,
state: State<AppState>,
claims: Claims,
) -> Result<Json<TagItem>, (StatusCode, String)> {
let uid: i64 = claims.uid.clone();
let tag_query = Tag::find()
.filter(TagColumn::Uid.eq(uid))
.filter(TagColumn::Id.eq(id))
.one(&state.conn)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let tag_resp: TagItem;
match tag_query {
Some(b) => {
tag_resp = TagItem {
id: b.id.into(),
name: b.name,
};
}
_ => {
return Err((StatusCode::NOT_FOUND, "not_found".to_string()));
}
}
Ok(Json(tag_resp))
}
#[debug_handler]
async fn create_tag(
state: State<AppState>,
claims: Claims,
Json(payload): Json<TagInfo>,
) -> Result<Json<SimpleResponse>, (StatusCode, String)> {
let uid: i64 = claims.uid.clone();
let tag = TagActiveModel {
name: Set(payload.name.clone().to_owned()),
uid: Set(uid.to_owned()),
..Default::default()
};
let res = Tag::insert(tag).exec(&state.conn).await;
let mut err_code: i64 = 0;
let mut msg: String;
match res {
Ok(_) => {
err_code = 0;
msg = "ok".to_owned();
}
Err(e) => {
err_code = 0;
msg = e.to_string();
}
}
let resp = SimpleResponse {
code: err_code,
message: msg,
};
Ok(Json(resp))
}
#[debug_handler]
async fn update_tag(
Path(id): Path<i64>,
state: State<AppState>,
claims: Claims,
Json(payload): Json<TagInfo>,
) -> Result<Json<SimpleResponse>, (StatusCode, String)> {
let uid: i64 = claims.uid.clone();
let exist_tag = Tag::find()
.filter(TagColumn::Uid.eq(uid))
.filter(TagColumn::Id.eq(id))
.one(&state.conn)
.await;
let tag: TagModel;
let mut resp = SimpleResponse {
code: 0,
message: "ok".to_owned(),
};
match exist_tag {
Ok(b) => match b {
Some(bk) => {
tag = bk;
}
_ => return Err((StatusCode::NOT_FOUND, "not_found".to_string())),
},
Err(_) => {
resp.code = 1;
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"connection_error".to_string(),
));
}
}
let mut tag_active_model: TagActiveModel = tag.into();
tag_active_model.name = Set(payload.name.clone());
tag_active_model.updated_at = Set(Local::now().naive_utc());
let update_res = tag_active_model.update(&state.conn).await;
match update_res {
Ok(_) => {
resp.code = 0;
resp.message = "ok".to_owned();
}
Err(_) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
"tag_update_fail".to_string(),
));
}
}
Ok(Json(resp))
}

View File

@@ -107,6 +107,7 @@ async fn start_server(config: &Config) {
let app = Router::new() let app = Router::new()
.nest("/api/v1/book", api::book::get_nest_handlers()) .nest("/api/v1/book", api::book::get_nest_handlers())
.nest("/api/v1/category", api::category::get_nested_handlers()) .nest("/api/v1/category", api::category::get_nested_handlers())
.nest("/api/v1/tag", api::tag::get_nest_handlers())
.with_state(state) .with_state(state)
.layer(global_layer); .layer(global_layer);
let host = config.service.host.clone(); let host = config.service.host.clone();

View File

@@ -1,3 +1,4 @@
pub mod book; pub mod book;
pub mod common; pub mod common;
pub mod category; pub mod category;
pub mod tag;

View File

@@ -0,0 +1,14 @@
use serde::{Serialize, Deserialize};
use super::common::{number_stringify, OptionalI64};
#[derive(Serialize)]
pub struct TagItem {
#[serde(with="number_stringify")]
pub id: OptionalI64,
pub name: String,
}
#[derive(Serialize,Deserialize)]
pub struct TagInfo {
pub name: String,
}