feat: account
This commit is contained in:
@@ -4,6 +4,8 @@ CREATE TABLE "categories" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"uid" BIGINT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"level" INT NOT NULL DEFAULT 0,
|
||||
"parent_category_id" BIGINT NOT NULL DEFAULT 0,
|
||||
"is_delete" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
"create_at" TIMESTAMP NOT NULL DEFAULT current_timestamp,
|
||||
"update_at" TIMESTAMP NOT NULL DEFAULT current_timestamp
|
||||
@@ -13,6 +15,8 @@ CREATE TABLE "tags" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"uid" BIGINT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"level" INT NOT NULL DEFAULT 0,
|
||||
"parent_tag_id" BIGINT NOT NULL DEFAULT 0,
|
||||
"is_delete" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
"create_at" TIMESTAMP NOT NULL DEFAULT current_timestamp,
|
||||
"update_at" TIMESTAMP NOT NULL DEFAULT current_timestamp
|
||||
@@ -53,7 +57,7 @@ CREATE TABLE "accounts" (
|
||||
"id" BIGSERIAL PRIMARY KEY,
|
||||
"uid" BIGINT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"type" BIGINT NOT NULL DEFAULT 0,
|
||||
"account_type" BIGINT NOT NULL DEFAULT 0,
|
||||
"is_delete" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
"create_at" TIMESTAMP NOT NULL DEFAULT current_timestamp,
|
||||
"update_at" TIMESTAMP NOT NULL DEFAULT current_timestamp
|
||||
|
||||
150
src/ledger/account.rs
Normal file
150
src/ledger/account.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
// use std::sync::Arc;
|
||||
use axum::routing::{get, post};
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
Json, Router,
|
||||
};
|
||||
use axum_macros::debug_handler;
|
||||
use diesel::prelude::*;
|
||||
// use diesel::update;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use serde_json::to_string;
|
||||
use crate::model::db_model;
|
||||
use crate::model::schema;
|
||||
use crate::util;
|
||||
use crate::util::req::CommonResp;
|
||||
use chrono::prelude::*;
|
||||
use tracing::info;
|
||||
use crate::middleware::auth;
|
||||
use crate::middleware::auth::Claims;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateAccountRequest {
|
||||
name: String,
|
||||
account_type: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct CreateAccountResponse {
|
||||
id: i64,
|
||||
name: String,
|
||||
account_type: i64,
|
||||
}
|
||||
|
||||
pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||
Router::new()
|
||||
.route("/", post(create_account).get(get_all_accounts))
|
||||
.route("/:id", post(update_account).get(get_account))
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn create_account(
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
Json(payload): Json<CreateAccountRequest>,
|
||||
) -> Result<Json<db_model::Account>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let new_account = db_model::AccountForm {
|
||||
name: payload.name,
|
||||
account_type: payload.account_type,
|
||||
uid: uid,
|
||||
};
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
diesel::insert_into(schema::accounts::table)
|
||||
.values(&new_account)
|
||||
.returning(db_model::Account::as_returning())
|
||||
.get_result(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
||||
pub async fn update_account(
|
||||
Path(id): Path<i64>,
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
Json(payload): Json<CreateAccountRequest>,
|
||||
) -> Result<Json<CommonResp>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let now = Utc::now().naive_utc();
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
diesel::update(schema::accounts::table)
|
||||
.filter(schema::accounts::id.eq(id))
|
||||
.filter(schema::accounts::uid.eq(uid))
|
||||
.set((
|
||||
schema::accounts::name.eq(payload.name),
|
||||
schema::accounts::account_type.eq(payload.account_type),
|
||||
schema::accounts::update_at.eq(now),
|
||||
))
|
||||
.execute(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
let resp = util::req::CommonResp { code: 0 };
|
||||
Ok(Json(resp))
|
||||
}
|
||||
|
||||
pub async fn get_account(
|
||||
Path(id): Path<i64>,
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<db_model::Account>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
schema::accounts::table
|
||||
.filter(schema::accounts::id.eq(id))
|
||||
.filter(schema::accounts::uid.eq(uid))
|
||||
.select(db_model::Account::as_select())
|
||||
.limit(1)
|
||||
.get_result(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
||||
pub async fn get_all_accounts(
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<Vec<db_model::Account>>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
schema::accounts::table
|
||||
.filter(schema::accounts::uid.eq(uid))
|
||||
.select(db_model::Account::as_select())
|
||||
.load(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
145
src/ledger/book.rs
Normal file
145
src/ledger/book.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
use axum::routing::{get, post};
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
Json, Router,
|
||||
};
|
||||
use axum_macros::debug_handler;
|
||||
use diesel::prelude::*;
|
||||
// use diesel::update;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use serde_json::to_string;
|
||||
use crate::model::db_model;
|
||||
use crate::model::schema;
|
||||
use crate::util;
|
||||
use crate::util::req::CommonResp;
|
||||
use chrono::prelude::*;
|
||||
use tracing::info;
|
||||
use crate::middleware::auth;
|
||||
use crate::middleware::auth::Claims;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateBookRequest {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct CreateBookResponse {
|
||||
id: i64,
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||
Router::new()
|
||||
.route("/", post(create_book).get(get_all_books))
|
||||
.route("/:id", post(update_book).get(get_book))
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
pub async fn create_book(
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
Json(payload): Json<CreateBookRequest>,
|
||||
) -> Result<Json<db_model::Book>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let new_book = db_model::BookForm {
|
||||
name: payload.name,
|
||||
uid,
|
||||
};
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
diesel::insert_into(schema::books::table)
|
||||
.values(&new_book)
|
||||
.returning(db_model::Book::as_returning())
|
||||
.get_result(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
||||
pub async fn update_book(
|
||||
Path(id): Path<i64>,
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
Json(payload): Json<CreateBookRequest>,
|
||||
) -> Result<Json<CommonResp>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let now = Utc::now().naive_utc();
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
diesel::update(schema::books::table)
|
||||
.filter(schema::books::id.eq(id))
|
||||
.filter(schema::books::uid.eq(uid))
|
||||
.set((
|
||||
schema::books::name.eq(payload.name),
|
||||
schema::books::update_at.eq(now),
|
||||
))
|
||||
.execute(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
let resp = util::req::CommonResp { code: 0 };
|
||||
Ok(Json(resp))
|
||||
}
|
||||
|
||||
pub async fn get_book(
|
||||
Path(id): Path<i64>,
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<db_model::Book>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
schema::books::table
|
||||
.filter(schema::books::id.eq(id))
|
||||
.filter(schema::books::uid.eq(uid))
|
||||
.select(db_model::Book::as_select())
|
||||
.limit(1)
|
||||
.get_result(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
||||
pub async fn get_all_books(
|
||||
State(app_state): State<crate::AppState>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<Vec<db_model::Book>>, (StatusCode, String)> {
|
||||
let uid: i64 = claims.uid.clone();
|
||||
let conn = app_state
|
||||
.db
|
||||
.get()
|
||||
.await
|
||||
.map_err(util::req::internal_error)?;
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
schema::books::table
|
||||
.filter(schema::books::uid.eq(uid))
|
||||
.select(db_model::Book::as_select())
|
||||
.load(conn)
|
||||
})
|
||||
.await
|
||||
.map_err(util::req::internal_error)?
|
||||
.map_err(util::req::internal_error)?;
|
||||
Ok(Json(res))
|
||||
}
|
||||
@@ -24,6 +24,8 @@ use crate::middleware::auth::Claims;
|
||||
pub struct CreateCategoryResponse {
|
||||
id: i64,
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_category_id: i64,
|
||||
}
|
||||
|
||||
pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||
@@ -35,6 +37,8 @@ pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateCategoryRequest {
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_category_id: i64,
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
@@ -52,7 +56,9 @@ pub async fn create_category(
|
||||
.map_err(util::req::internal_error)?;
|
||||
let new_category = db_model::CategoryForm {
|
||||
name: payload.name,
|
||||
uid,
|
||||
uid: uid,
|
||||
level: payload.level,
|
||||
parent_category_id: payload.parent_category_id,
|
||||
};
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
@@ -89,6 +95,8 @@ pub async fn update_category(
|
||||
.filter(schema::categories::uid.eq(uid))
|
||||
.set((
|
||||
schema::categories::name.eq(payload.name),
|
||||
schema::categories::level.eq(payload.level),
|
||||
schema::categories::parent_category_id.eq(payload.parent_category_id),
|
||||
schema::categories::update_at.eq(now),
|
||||
))
|
||||
.execute(conn)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
pub mod category;
|
||||
pub mod tag;
|
||||
pub mod book;
|
||||
pub mod account;
|
||||
@@ -22,12 +22,16 @@ use crate::middleware::auth::Claims;
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateTagRequest {
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_tag_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct CreateTagResponse {
|
||||
id: i64,
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_tag_id: i64,
|
||||
}
|
||||
|
||||
pub fn get_nest_handlers() -> Router<crate::AppState> {
|
||||
@@ -50,7 +54,9 @@ pub async fn create_tag(
|
||||
.map_err(util::req::internal_error)?;
|
||||
let new_tag = db_model::TagForm {
|
||||
name: payload.name,
|
||||
uid,
|
||||
uid: uid,
|
||||
level: payload.level,
|
||||
parent_tag_id: payload.parent_tag_id,
|
||||
};
|
||||
let res = conn
|
||||
.interact(move |conn| {
|
||||
@@ -85,6 +91,8 @@ pub async fn update_tag(
|
||||
.filter(schema::tags::uid.eq(uid))
|
||||
.set((
|
||||
schema::tags::name.eq(payload.name),
|
||||
schema::tags::level.eq(payload.level),
|
||||
schema::tags::parent_tag_id.eq(payload.parent_tag_id),
|
||||
schema::tags::update_at.eq(now),
|
||||
))
|
||||
.execute(conn)
|
||||
|
||||
@@ -93,6 +93,8 @@ async fn main() {
|
||||
// V1 apis
|
||||
.nest("/api/v1/category", ledger::category::get_nest_handlers())
|
||||
.nest("/api/v1/tag", ledger::tag::get_nest_handlers())
|
||||
.nest("/api/v1/book", ledger::book::get_nest_handlers())
|
||||
.nest("/api/v1/account", ledger::account::get_nest_handlers())
|
||||
.nest("/api/v1/user", user::handler::get_nest_handlers())
|
||||
.with_state(shared_state)
|
||||
.layer(global_layer);
|
||||
|
||||
@@ -8,6 +8,8 @@ pub struct Category {
|
||||
id: i64,
|
||||
uid: i64,
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_category_id: i64,
|
||||
is_delete: bool,
|
||||
create_at: chrono::NaiveDateTime,
|
||||
update_at: chrono::NaiveDateTime,
|
||||
@@ -18,6 +20,8 @@ pub struct Category {
|
||||
pub struct CategoryForm {
|
||||
pub uid: i64,
|
||||
pub name: String,
|
||||
pub level: i32,
|
||||
pub parent_category_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, serde::Serialize, serde::Deserialize)]
|
||||
@@ -27,6 +31,8 @@ pub struct Tag {
|
||||
id: i64,
|
||||
uid: i64,
|
||||
name: String,
|
||||
level: i32,
|
||||
parent_tag_id: i64,
|
||||
is_delete: bool,
|
||||
create_at: chrono::NaiveDateTime,
|
||||
update_at: chrono::NaiveDateTime,
|
||||
@@ -37,6 +43,49 @@ pub struct Tag {
|
||||
pub struct TagForm {
|
||||
pub uid: i64,
|
||||
pub name: String,
|
||||
pub level: i32,
|
||||
pub parent_tag_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, serde::Serialize, serde::Deserialize)]
|
||||
#[diesel(table_name = schema::books)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Book {
|
||||
id: i64,
|
||||
uid: i64,
|
||||
name: String,
|
||||
is_delete: bool,
|
||||
create_at: chrono::NaiveDateTime,
|
||||
update_at: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Insertable)]
|
||||
#[diesel(table_name = schema::books)]
|
||||
pub struct BookForm {
|
||||
pub uid: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Queryable, Selectable, serde::Serialize, serde::Deserialize)]
|
||||
#[diesel(table_name = schema::accounts)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Account {
|
||||
id: i64,
|
||||
uid: i64,
|
||||
name: String,
|
||||
account_type: i64,
|
||||
is_delete: bool,
|
||||
create_at: chrono::NaiveDateTime,
|
||||
update_at: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Insertable)]
|
||||
#[diesel(table_name = schema::accounts)]
|
||||
pub struct AccountForm {
|
||||
pub uid: i64,
|
||||
pub name: String,
|
||||
pub account_type: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, serde::Serialize)]
|
||||
|
||||
@@ -5,8 +5,7 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
#[sql_name = "type"]
|
||||
type_ -> Int8,
|
||||
account_type -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
@@ -42,6 +41,8 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
level -> Int4,
|
||||
parent_category_id -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
@@ -53,6 +54,8 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
level -> Int4,
|
||||
parent_tag_id -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
|
||||
@@ -5,8 +5,7 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
#[sql_name = "type"]
|
||||
type_ -> Int8,
|
||||
account_type -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
@@ -42,6 +41,8 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
level -> Int4,
|
||||
parent_category_id -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
@@ -53,6 +54,8 @@ diesel::table! {
|
||||
id -> Int8,
|
||||
uid -> Int8,
|
||||
name -> Text,
|
||||
level -> Int4,
|
||||
parent_tag_id -> Int8,
|
||||
is_delete -> Bool,
|
||||
create_at -> Timestamp,
|
||||
update_at -> Timestamp,
|
||||
|
||||
Reference in New Issue
Block a user