Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- 新增 SaaS industry 模块 (types/service/handlers/mod/builtin) - 4 行业内置配置: healthcare/education/garment/ecommerce - 数据库迁移: industries + account_industries 表 - 8 个 API 端点 (CRUD + 用户行业关联) - ButlerRouter 改造: 支持 IndustryKeywordConfig 动态注入 - 12 个测试全通过 (含动态行业分类测试)
112 lines
3.8 KiB
Rust
112 lines
3.8 KiB
Rust
//! 行业配置 API handlers
|
||
|
||
use axum::extract::{Path, Query, State};
|
||
use axum::Extension;
|
||
use axum::Json;
|
||
use crate::error::SaasResult;
|
||
use crate::state::AppState;
|
||
use crate::auth::types::AuthContext;
|
||
use super::types::*;
|
||
use super::service;
|
||
|
||
/// GET /api/v1/industries — 行业列表(公开,已认证用户可访问)
|
||
pub async fn list_industries(
|
||
State(state): State<AppState>,
|
||
Query(query): Query<ListIndustriesQuery>,
|
||
) -> SaasResult<Json<crate::common::PaginatedResponse<IndustryListItem>>> {
|
||
let result = service::list_industries(&state.db, &query).await?;
|
||
Ok(Json(result))
|
||
}
|
||
|
||
/// GET /api/v1/industries/:id — 行业详情(公开)
|
||
pub async fn get_industry(
|
||
State(state): State<AppState>,
|
||
Path(id): Path<String>,
|
||
) -> SaasResult<Json<Industry>> {
|
||
let industry = service::get_industry(&state.db, &id).await?;
|
||
Ok(Json(industry))
|
||
}
|
||
|
||
/// POST /api/v1/industries — 创建行业 (admin: config:write)
|
||
pub async fn create_industry(
|
||
State(state): State<AppState>,
|
||
Extension(ctx): Extension<AuthContext>,
|
||
Json(body): Json<CreateIndustryRequest>,
|
||
) -> SaasResult<Json<Industry>> {
|
||
require_config_write(&ctx)?;
|
||
let industry = service::create_industry(&state.db, &body).await?;
|
||
Ok(Json(industry))
|
||
}
|
||
|
||
/// PATCH /api/v1/industries/:id — 更新行业 (admin: config:write)
|
||
pub async fn update_industry(
|
||
State(state): State<AppState>,
|
||
Extension(ctx): Extension<AuthContext>,
|
||
Path(id): Path<String>,
|
||
Json(body): Json<UpdateIndustryRequest>,
|
||
) -> SaasResult<Json<Industry>> {
|
||
require_config_write(&ctx)?;
|
||
let industry = service::update_industry(&state.db, &id, &body).await?;
|
||
Ok(Json(industry))
|
||
}
|
||
|
||
/// GET /api/v1/industries/:id/full-config — 完整配置(含关键词、prompt等)
|
||
pub async fn get_industry_full_config(
|
||
State(state): State<AppState>,
|
||
Path(id): Path<String>,
|
||
) -> SaasResult<Json<IndustryFullConfig>> {
|
||
let config = service::get_industry_full_config(&state.db, &id).await?;
|
||
Ok(Json(config))
|
||
}
|
||
|
||
/// GET /api/v1/accounts/:id/industries — 用户授权行业列表
|
||
pub async fn list_account_industries(
|
||
State(state): State<AppState>,
|
||
Path(account_id): Path<String>,
|
||
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
|
||
let items = service::list_account_industries(&state.db, &account_id).await?;
|
||
Ok(Json(items))
|
||
}
|
||
|
||
/// PUT /api/v1/accounts/:id/industries — 设置用户行业 (admin: account:admin)
|
||
pub async fn set_account_industries(
|
||
State(state): State<AppState>,
|
||
Extension(ctx): Extension<AuthContext>,
|
||
Path(account_id): Path<String>,
|
||
Json(body): Json<SetAccountIndustriesRequest>,
|
||
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
|
||
require_account_admin(&ctx)?;
|
||
let items = service::set_account_industries(&state.db, &account_id, &body).await?;
|
||
Ok(Json(items))
|
||
}
|
||
|
||
/// GET /api/v1/accounts/me/industries — 当前用户行业
|
||
pub async fn list_my_industries(
|
||
State(state): State<AppState>,
|
||
Extension(ctx): Extension<AuthContext>,
|
||
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
|
||
let account_id = &ctx.account_id;
|
||
let items = service::list_account_industries(&state.db, account_id).await?;
|
||
Ok(Json(items))
|
||
}
|
||
|
||
// ============ Helpers ============
|
||
|
||
fn require_config_write(ctx: &AuthContext) -> SaasResult<()> {
|
||
if !ctx.permissions.contains(&"config:write".to_string())
|
||
&& !ctx.permissions.contains(&"admin:full".to_string())
|
||
{
|
||
return Err(crate::error::SaasError::Forbidden("需要 config:write 权限".to_string()));
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
fn require_account_admin(ctx: &AuthContext) -> SaasResult<()> {
|
||
if !ctx.permissions.contains(&"account:admin".to_string())
|
||
&& !ctx.permissions.contains(&"admin:full".to_string())
|
||
{
|
||
return Err(crate::error::SaasError::Forbidden("需要 account:admin 权限".to_string()));
|
||
}
|
||
Ok(())
|
||
}
|