Compare commits
2 Commits
891982ede0
...
dev/v1-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f915e72cf5 | ||
|
|
33cb0aaa33 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,4 +4,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.env
|
.env
|
||||||
conf.toml
|
conf.toml
|
||||||
|
config.toml
|
||||||
.fleet\
|
.fleet\
|
||||||
62
src/api/account.rs
Normal file
62
src/api/account.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use crate::middleware::auth::Claims;
|
||||||
|
use crate::model::db::account::{
|
||||||
|
ActiveModel as AccountActiveModel, Column as AccountColumn, Model as AccountModel,
|
||||||
|
};
|
||||||
|
use crate::model::db::prelude::Account as AccountPrelude;
|
||||||
|
use crate::model::http_body::account::{AccountReq, AccountResp};
|
||||||
|
use crate::model::http_body::common::SimpleResponse;
|
||||||
|
use crate::AppState;
|
||||||
|
use axum::extract::{Path, State};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum::routing::{get, post};
|
||||||
|
use axum::{Json, Router};
|
||||||
|
use sea_orm::sqlx::types::chrono::Local;
|
||||||
|
use sea_orm::{ActiveModelTrait, DbErr, Iden, Set};
|
||||||
|
|
||||||
|
pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||||
|
Router::new()
|
||||||
|
.route("/{id}/update", post(update_account_handler))
|
||||||
|
.route("/{id}", get(get_account_by_id_handler))
|
||||||
|
.route(
|
||||||
|
"/",
|
||||||
|
post(create_account_handler).get(get_all_accounts_handler),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_account_handler(
|
||||||
|
Path(id): Path<i64>,
|
||||||
|
state: State<AppState>,
|
||||||
|
claims: Claims,
|
||||||
|
Json(payload): Json<AccountReq>,
|
||||||
|
) -> Result<Json<SimpleResponse>, (StatusCode, String)> {
|
||||||
|
let uid: i64 = claims.uid.clone();
|
||||||
|
let mut active_model: AccountActiveModel = AccountPrelude::find_by_id(id)
|
||||||
|
.filter(AccountColumn::Uid.eq(uid))
|
||||||
|
.filter(AccountColumn::IsDeleted.eq(false))
|
||||||
|
.one(&state.conn)
|
||||||
|
.await
|
||||||
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||||
|
match payload.name {
|
||||||
|
Some(n) => {
|
||||||
|
active_model.name = Set(n);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
active_model.updated_at = Set(Local::now().naive_utc());
|
||||||
|
|
||||||
|
active_model.update(&state.conn).await
|
||||||
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||||
|
|
||||||
|
let resp = SimpleResponse{
|
||||||
|
code: 0,
|
||||||
|
message: "".to_string()
|
||||||
|
};
|
||||||
|
Ok(Json(resp))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_account_by_id_handler() {}
|
||||||
|
|
||||||
|
async fn create_account_handler() {}
|
||||||
|
|
||||||
|
async fn get_all_accounts_handler() {}
|
||||||
198
src/api/book_test.rs
Normal file
198
src/api/book_test.rs
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
// #[cfg(test)]
|
||||||
|
// mod tests {
|
||||||
|
// use super::*;
|
||||||
|
// use axum::{
|
||||||
|
// http::{Request, StatusCode},
|
||||||
|
// Router,
|
||||||
|
// routing::{get, put},
|
||||||
|
// body::Body,
|
||||||
|
// };
|
||||||
|
// use sea_orm::{
|
||||||
|
// MockDatabase, MockExecResult, DatabaseConnection, DatabaseTransaction,
|
||||||
|
// entity::prelude::*,
|
||||||
|
// QueryFilter, Condition, DbErr, EntityTrait,
|
||||||
|
// };
|
||||||
|
// use serde_json::{json, Value};
|
||||||
|
// use tower::ServiceExt;
|
||||||
|
// use std::sync::Arc;
|
||||||
|
//
|
||||||
|
// // 模拟 Book 实体
|
||||||
|
// #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
// #[sea_orm(table_name = "books")]
|
||||||
|
// pub struct Model {
|
||||||
|
// #[sea_orm(primary_key)]
|
||||||
|
// pub id: i32,
|
||||||
|
// pub title: String,
|
||||||
|
// pub author: String,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
|
// pub enum Relation {}
|
||||||
|
//
|
||||||
|
// impl Related<super::book::Entity> for Entity {
|
||||||
|
// fn to() -> RelationDef {
|
||||||
|
// panic!("No relations defined")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 创建测试用的 Router
|
||||||
|
// async fn setup_router(db: DatabaseConnection) -> Router {
|
||||||
|
// Router::new()
|
||||||
|
// .route("/books/:id", get(get_book_by_id).put(update_book_by_id))
|
||||||
|
// .route("/books", get(get_all_book))
|
||||||
|
// .with_state(Arc::new(db))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 测试 get_book_by_id
|
||||||
|
// #[tokio::test]
|
||||||
|
// async fn test_get_book_by_id() {
|
||||||
|
// // 设置模拟数据库
|
||||||
|
// let db = MockDatabase::new(DatabaseBackend::Postgres)
|
||||||
|
// .append_query_results(vec![vec![Model {
|
||||||
|
// id: 1,
|
||||||
|
// title: "Test Book".to_string(),
|
||||||
|
// author: "Test Author".to_string(),
|
||||||
|
// }]])
|
||||||
|
// .into_connection();
|
||||||
|
//
|
||||||
|
// let app = setup_router(db).await;
|
||||||
|
//
|
||||||
|
// // 构造请求
|
||||||
|
// let request = Request::builder()
|
||||||
|
// .uri("/books/1")
|
||||||
|
// .method("GET")
|
||||||
|
// .body(Body::empty())
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// // 发送请求
|
||||||
|
// let response = app.oneshot(request).await.unwrap();
|
||||||
|
// assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
//
|
||||||
|
// // 解析响应
|
||||||
|
// let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
// let body: Value = serde_json::from_slice(&body).unwrap();
|
||||||
|
// assert_eq!(
|
||||||
|
// body,
|
||||||
|
// json!({
|
||||||
|
// "id": 1,
|
||||||
|
// "title": "Test Book",
|
||||||
|
// "author": "Test Author"
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 测试 get_book_by_id 未找到
|
||||||
|
// #[tokio::test]
|
||||||
|
// async fn test_get_book_by_id_not_found() {
|
||||||
|
// let db = MockDatabase::new(DatabaseBackend::Postgres)
|
||||||
|
// .append_query_results(vec![vec![] as Vec<Model>])
|
||||||
|
// .into_connection();
|
||||||
|
//
|
||||||
|
// let app = setup_router(db).await;
|
||||||
|
//
|
||||||
|
// let request = Request::builder()
|
||||||
|
// .uri("/books/999")
|
||||||
|
// .method("GET")
|
||||||
|
// .body(Body::empty())
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// let response = app.oneshot(request).await.unwrap();
|
||||||
|
// assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 测试 update_book_by_id
|
||||||
|
// #[tokio::test]
|
||||||
|
// async fn test_update_book_by_id() {
|
||||||
|
// let db = MockDatabase::new(DatabaseBackend::Postgres)
|
||||||
|
// .append_query_results(vec![vec![Model {
|
||||||
|
// id: 1,
|
||||||
|
// title: "Updated Book".to_string(),
|
||||||
|
// author: "Updated Author".to_string(),
|
||||||
|
// }]])
|
||||||
|
// .append_exec_results(vec![MockExecResult {
|
||||||
|
// last_insert_id: 1,
|
||||||
|
// rows_affected: 1,
|
||||||
|
// }])
|
||||||
|
// .into_connection();
|
||||||
|
//
|
||||||
|
// let app = setup_router(db).await;
|
||||||
|
//
|
||||||
|
// // 构造请求
|
||||||
|
// let request = Request::builder()
|
||||||
|
// .uri("/books/1")
|
||||||
|
// .method("PUT")
|
||||||
|
// .header("Content-Type", "application/json")
|
||||||
|
// .body(Body::from(
|
||||||
|
// json!({
|
||||||
|
// "title": "Updated Book",
|
||||||
|
// "author": "Updated Author"
|
||||||
|
// })
|
||||||
|
// .to_string(),
|
||||||
|
// ))
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// // 发送请求
|
||||||
|
// let response = app.oneshot(request).await.unwrap();
|
||||||
|
// assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
//
|
||||||
|
// // 解析响应
|
||||||
|
// let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
// let body: Value = serde_json::from_slice(&body).unwrap();
|
||||||
|
// assert_eq!(
|
||||||
|
// body,
|
||||||
|
// json!({
|
||||||
|
// "id": 1,
|
||||||
|
// "title": "Updated Book",
|
||||||
|
// "author": "Updated Author"
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 测试 get_all_book
|
||||||
|
// #[tokio::test]
|
||||||
|
// async fn test_get_all_book() {
|
||||||
|
// let db = MockDatabase::new(DatabaseBackend::Postgres)
|
||||||
|
// .append_query_results(vec![vec![
|
||||||
|
// Model {
|
||||||
|
// id: 1,
|
||||||
|
// title: "Book 1".to_string(),
|
||||||
|
// author: "Author 1".to_string(),
|
||||||
|
// },
|
||||||
|
// Model {
|
||||||
|
// id: 2,
|
||||||
|
// title: "Book 2".to_string(),
|
||||||
|
// author: "Author 2".to_string(),
|
||||||
|
// },
|
||||||
|
// ]])
|
||||||
|
// .into_connection();
|
||||||
|
//
|
||||||
|
// let app = setup_router(db).await;
|
||||||
|
//
|
||||||
|
// let request = Request::builder()
|
||||||
|
// .uri("/books")
|
||||||
|
// .method("GET")
|
||||||
|
// .body(Body::empty())
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// let response = app.oneshot(request).await.unwrap();
|
||||||
|
// assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
//
|
||||||
|
// let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
|
||||||
|
// let body: Value = serde_json::from_slice(&body).unwrap();
|
||||||
|
// assert_eq!(
|
||||||
|
// body,
|
||||||
|
// json!([
|
||||||
|
// {
|
||||||
|
// "id": 1,
|
||||||
|
// "title": "Book 1",
|
||||||
|
// "author": "Author 1"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": 2,
|
||||||
|
// "title": "Book 2",
|
||||||
|
// "author": "Author 2"
|
||||||
|
// }
|
||||||
|
// ])
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -2,3 +2,4 @@ pub mod book;
|
|||||||
pub mod category;
|
pub mod category;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
pub mod account;
|
||||||
@@ -114,6 +114,7 @@ async fn start_server(config: &Config) {
|
|||||||
.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())
|
.nest("/api/v1/tag", api::tag::get_nest_handlers())
|
||||||
|
.nest("/api/v1/transaction", api::transaction::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();
|
||||||
|
|||||||
14
src/model/http_body/account.rs
Normal file
14
src/model/http_body/account.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct AccountResp {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub account_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct AccountReq {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub account_type: Option<String>,
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ pub mod common;
|
|||||||
pub mod category;
|
pub mod category;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
pub mod account;
|
||||||
|
|||||||
@@ -19,3 +19,7 @@
|
|||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TransactionAmountReq {
|
||||||
|
pub id: Option<String>,
|
||||||
|
pub account_id: Option<String>,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user