feat(project): init
This commit is contained in:
247
src/api/handlers/column.rs
Normal file
247
src/api/handlers/column.rs
Normal file
@@ -0,0 +1,247 @@
|
||||
use axum::{
|
||||
Json, Router,
|
||||
extract::{Path, Query, State},
|
||||
routing::{get, post},
|
||||
};
|
||||
use common_telemetry::{AppError, AppResponse};
|
||||
use utoipa::IntoParams;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::api::{AppState, handlers::common::extract_bearer_token};
|
||||
use auth_kit::middleware::{tenant::TenantId, auth::AuthContext};
|
||||
|
||||
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct CreateColumnRequest {
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub description: Option<String>,
|
||||
pub parent_id: Option<Uuid>,
|
||||
pub sort_order: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, utoipa::ToSchema)]
|
||||
pub struct UpdateColumnRequest {
|
||||
pub name: Option<String>,
|
||||
pub slug: Option<String>,
|
||||
pub description: Option<Option<String>>,
|
||||
pub parent_id: Option<Option<Uuid>>,
|
||||
pub sort_order: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, IntoParams)]
|
||||
pub struct ListColumnsQuery {
|
||||
pub page: Option<u32>,
|
||||
pub page_size: Option<u32>,
|
||||
pub search: Option<String>,
|
||||
pub parent_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
pub fn router() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/", post(create_column_handler).get(list_columns_handler))
|
||||
.route(
|
||||
"/{id}",
|
||||
get(get_column_handler)
|
||||
.patch(update_column_handler)
|
||||
.delete(delete_column_handler),
|
||||
)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/v1/columns",
|
||||
tag = "Column",
|
||||
request_body = CreateColumnRequest,
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "创建栏目", body = crate::domain::models::Column),
|
||||
(status = 401, description = "未认证"),
|
||||
(status = 403, description = "无权限")
|
||||
)
|
||||
)]
|
||||
pub async fn create_column_handler(
|
||||
TenantId(tenant_id): TenantId,
|
||||
AuthContext { user_id, .. }: AuthContext,
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Json(body): Json<CreateColumnRequest>,
|
||||
) -> Result<AppResponse<crate::domain::models::Column>, AppError> {
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
state
|
||||
.iam_client
|
||||
.require_permission(tenant_id, user_id, "cms:column:write", &token)
|
||||
.await?;
|
||||
|
||||
let column = state
|
||||
.services
|
||||
.create_column(
|
||||
tenant_id,
|
||||
body.name,
|
||||
body.slug,
|
||||
body.description,
|
||||
body.parent_id,
|
||||
body.sort_order.unwrap_or(0),
|
||||
)
|
||||
.await?;
|
||||
Ok(AppResponse::ok(column))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/v1/columns",
|
||||
tag = "Column",
|
||||
params(ListColumnsQuery),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "栏目列表", body = crate::infrastructure::repositories::column::Paged<crate::domain::models::Column>),
|
||||
(status = 401, description = "未认证"),
|
||||
(status = 403, description = "无权限")
|
||||
)
|
||||
)]
|
||||
pub async fn list_columns_handler(
|
||||
TenantId(tenant_id): TenantId,
|
||||
AuthContext { user_id, .. }: AuthContext,
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(query): Query<ListColumnsQuery>,
|
||||
) -> Result<AppResponse<crate::infrastructure::repositories::column::Paged<crate::domain::models::Column>>, AppError>
|
||||
{
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
state
|
||||
.iam_client
|
||||
.require_permission(tenant_id, user_id, "cms:column:read", &token)
|
||||
.await?;
|
||||
|
||||
let result = state
|
||||
.services
|
||||
.list_columns(
|
||||
tenant_id,
|
||||
crate::infrastructure::repositories::column::ListColumnsQuery {
|
||||
page: query.page.unwrap_or(1),
|
||||
page_size: query.page_size.unwrap_or(20),
|
||||
search: query.search,
|
||||
parent_id: query.parent_id,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
Ok(AppResponse::ok(result))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/v1/columns/{id}",
|
||||
tag = "Column",
|
||||
params(
|
||||
("id" = String, Path, description = "栏目ID")
|
||||
),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "栏目详情", body = crate::domain::models::Column),
|
||||
(status = 401, description = "未认证"),
|
||||
(status = 403, description = "无权限"),
|
||||
(status = 404, description = "不存在")
|
||||
)
|
||||
)]
|
||||
pub async fn get_column_handler(
|
||||
TenantId(tenant_id): TenantId,
|
||||
AuthContext { user_id, .. }: AuthContext,
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<AppResponse<crate::domain::models::Column>, AppError> {
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
state
|
||||
.iam_client
|
||||
.require_permission(tenant_id, user_id, "cms:column:read", &token)
|
||||
.await?;
|
||||
|
||||
let column = state.services.get_column(tenant_id, id).await?;
|
||||
Ok(AppResponse::ok(column))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
path = "/v1/columns/{id}",
|
||||
tag = "Column",
|
||||
request_body = UpdateColumnRequest,
|
||||
params(
|
||||
("id" = String, Path, description = "栏目ID")
|
||||
),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "更新栏目", body = crate::domain::models::Column),
|
||||
(status = 401, description = "未认证"),
|
||||
(status = 403, description = "无权限"),
|
||||
(status = 404, description = "不存在")
|
||||
)
|
||||
)]
|
||||
pub async fn update_column_handler(
|
||||
TenantId(tenant_id): TenantId,
|
||||
AuthContext { user_id, .. }: AuthContext,
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Path(id): Path<Uuid>,
|
||||
Json(body): Json<UpdateColumnRequest>,
|
||||
) -> Result<AppResponse<crate::domain::models::Column>, AppError> {
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
state
|
||||
.iam_client
|
||||
.require_permission(tenant_id, user_id, "cms:column:write", &token)
|
||||
.await?;
|
||||
|
||||
let column = state
|
||||
.services
|
||||
.update_column(
|
||||
tenant_id,
|
||||
id,
|
||||
body.name,
|
||||
body.slug,
|
||||
body.description,
|
||||
body.parent_id,
|
||||
body.sort_order,
|
||||
)
|
||||
.await?;
|
||||
Ok(AppResponse::ok(column))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/v1/columns/{id}",
|
||||
tag = "Column",
|
||||
params(
|
||||
("id" = String, Path, description = "栏目ID")
|
||||
),
|
||||
security(
|
||||
("bearer_auth" = [])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "删除成功"),
|
||||
(status = 401, description = "未认证"),
|
||||
(status = 403, description = "无权限"),
|
||||
(status = 404, description = "不存在")
|
||||
)
|
||||
)]
|
||||
pub async fn delete_column_handler(
|
||||
TenantId(tenant_id): TenantId,
|
||||
AuthContext { user_id, .. }: AuthContext,
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<AppResponse<serde_json::Value>, AppError> {
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
state
|
||||
.iam_client
|
||||
.require_permission(tenant_id, user_id, "cms:column:write", &token)
|
||||
.await?;
|
||||
|
||||
state.services.delete_column(tenant_id, id).await?;
|
||||
Ok(AppResponse::ok(serde_json::json!({"deleted": true})))
|
||||
}
|
||||
Reference in New Issue
Block a user