170 lines
5.2 KiB
Rust
170 lines
5.2 KiB
Rust
use axum::{
|
|
extract::{Path, State},
|
|
http::StatusCode,
|
|
Json,
|
|
};
|
|
use sea_orm::{prelude::Decimal, DatabaseConnection};
|
|
use serde::Deserialize;
|
|
use utoipa::ToSchema;
|
|
|
|
use crate::models::category::Model as CategoryModel;
|
|
use crate::services::CategoryService;
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
#[schema(example = json!({"name": "Groceries", "limit_amount": 5000.00}))]
|
|
pub struct CreateCategoryRequest {
|
|
pub name: String,
|
|
pub limit_amount: Decimal,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
#[schema(example = json!({"name": "Monthly Groceries", "limit_amount": 6000.00}))]
|
|
pub struct UpdateCategoryRequest {
|
|
pub name: Option<String>,
|
|
pub limit_amount: Option<Decimal>,
|
|
}
|
|
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/families/{family_id}/categories",
|
|
tag = "categories",
|
|
params(
|
|
("family_id" = i32, Path, description = "Family ID")
|
|
),
|
|
request_body = CreateCategoryRequest,
|
|
responses(
|
|
(status = 200, description = "Category created successfully", body = CategoryModel),
|
|
(status = 500, description = "Internal server error")
|
|
)
|
|
)]
|
|
pub async fn create_category(
|
|
State(db): State<DatabaseConnection>,
|
|
Path(family_id): Path<i32>,
|
|
Json(payload): Json<CreateCategoryRequest>,
|
|
) -> Result<Json<CategoryModel>, StatusCode> {
|
|
CategoryService::create(&db, family_id, payload.name, payload.limit_amount)
|
|
.await
|
|
.map(Json)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/families/{family_id}/categories/{category_id}",
|
|
tag = "categories",
|
|
params(
|
|
("family_id" = i32, Path, description = "Family ID"),
|
|
("category_id" = i32, Path, description = "Category ID")
|
|
),
|
|
responses(
|
|
(status = 200, description = "Category found", body = CategoryModel),
|
|
(status = 404, description = "Category not found"),
|
|
(status = 500, description = "Internal server error")
|
|
)
|
|
)]
|
|
pub async fn get_category(
|
|
State(db): State<DatabaseConnection>,
|
|
Path((family_id, category_id)): Path<(i32, i32)>,
|
|
) -> Result<Json<CategoryModel>, StatusCode> {
|
|
let category = CategoryService::find_by_id(&db, category_id)
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
.ok_or(StatusCode::NOT_FOUND)?;
|
|
|
|
if category.family_id != family_id {
|
|
return Err(StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
Ok(Json(category))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/families/{family_id}/categories",
|
|
tag = "categories",
|
|
params(
|
|
("family_id" = i32, Path, description = "Family ID")
|
|
),
|
|
responses(
|
|
(status = 200, description = "List of categories for the family", body = Vec<CategoryModel>),
|
|
(status = 500, description = "Internal server error")
|
|
)
|
|
)]
|
|
pub async fn get_categories_by_family(
|
|
State(db): State<DatabaseConnection>,
|
|
Path(family_id): Path<i32>,
|
|
) -> Result<Json<Vec<CategoryModel>>, StatusCode> {
|
|
CategoryService::find_by_family_id(&db, family_id)
|
|
.await
|
|
.map(Json)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
#[utoipa::path(
|
|
put,
|
|
path = "/families/{family_id}/categories/{category_id}",
|
|
tag = "categories",
|
|
params(
|
|
("family_id" = i32, Path, description = "Family ID"),
|
|
("category_id" = i32, Path, description = "Category ID")
|
|
),
|
|
request_body = UpdateCategoryRequest,
|
|
responses(
|
|
(status = 200, description = "Category updated successfully", body = CategoryModel),
|
|
(status = 404, description = "Category not found"),
|
|
(status = 500, description = "Internal server error")
|
|
)
|
|
)]
|
|
pub async fn update_category(
|
|
State(db): State<DatabaseConnection>,
|
|
Path((family_id, category_id)): Path<(i32, i32)>,
|
|
Json(payload): Json<UpdateCategoryRequest>,
|
|
) -> Result<Json<CategoryModel>, StatusCode> {
|
|
let category = CategoryService::find_by_id(&db, category_id)
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
.ok_or(StatusCode::NOT_FOUND)?;
|
|
|
|
if category.family_id != family_id {
|
|
return Err(StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
CategoryService::update(&db, category_id, payload.name, payload.limit_amount)
|
|
.await
|
|
.map(Json)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
#[utoipa::path(
|
|
delete,
|
|
path = "/families/{family_id}/categories/{category_id}",
|
|
tag = "categories",
|
|
params(
|
|
("family_id" = i32, Path, description = "Family ID"),
|
|
("category_id" = i32, Path, description = "Category ID")
|
|
),
|
|
responses(
|
|
(status = 204, description = "Category deleted successfully"),
|
|
(status = 404, description = "Category not found"),
|
|
(status = 500, description = "Internal server error")
|
|
)
|
|
)]
|
|
pub async fn delete_category(
|
|
State(db): State<DatabaseConnection>,
|
|
Path((family_id, category_id)): Path<(i32, i32)>,
|
|
) -> Result<StatusCode, StatusCode> {
|
|
let category = CategoryService::find_by_id(&db, category_id)
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
.ok_or(StatusCode::NOT_FOUND)?;
|
|
|
|
if category.family_id != family_id {
|
|
return Err(StatusCode::NOT_FOUND);
|
|
}
|
|
|
|
CategoryService::delete(&db, category_id)
|
|
.await
|
|
.map(|_| StatusCode::NO_CONTENT)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
}
|