Files
zclaw_openfang/crates/zclaw-saas/src/prompt/handlers.rs
iven 5fdf96c3f5 chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成
包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、
文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
2026-03-29 10:46:41 +08:00

174 lines
6.1 KiB
Rust

//! 提示词模板 HTTP 处理器
use axum::{
extract::{Extension, Path, Query, State},
Json,
};
use crate::state::AppState;
use crate::error::SaasResult;
use crate::auth::types::AuthContext;
use crate::auth::handlers::{log_operation, check_permission};
use super::types::*;
use super::service;
/// GET /api/v1/prompts/check — OTA 批量检查更新
pub async fn check_updates(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Json(req): Json<PromptCheckRequest>,
) -> SaasResult<Json<PromptCheckResponse>> {
let result = service::check_updates(&state.db, &req.device_id, &req.versions).await?;
log_operation(&state.db, &ctx.account_id, "prompt.check", "prompt", &req.device_id,
Some(serde_json::json!({"updates_count": result.updates.len()})), ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}
/// GET /api/v1/prompts — 列表全部模板
pub async fn list_prompts(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Query(query): Query<PromptListQuery>,
) -> SaasResult<Json<crate::common::PaginatedResponse<PromptTemplateInfo>>> {
check_permission(&ctx, "prompt:read")?;
Ok(Json(service::list_templates(&state.db, &query).await?))
}
/// POST /api/v1/prompts — 创建提示词模板
pub async fn create_prompt(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Json(req): Json<CreatePromptRequest>,
) -> SaasResult<Json<PromptTemplateInfo>> {
check_permission(&ctx, "prompt:write")?;
let source = req.source.as_deref().unwrap_or("custom");
let result = service::create_template(
&state.db, &req.name, &req.category, req.description.as_deref(),
source, &req.system_prompt,
req.user_prompt_template.as_deref(),
req.variables.clone(),
req.min_app_version.as_deref(),
).await?;
log_operation(&state.db, &ctx.account_id, "prompt.create", "prompt", &result.id,
Some(serde_json::json!({"name": req.name})), ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}
/// GET /api/v1/prompts/{name} — 获取模板(按名称)
pub async fn get_prompt(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(name): Path<String>,
) -> SaasResult<Json<PromptTemplateInfo>> {
check_permission(&ctx, "prompt:read")?;
Ok(Json(service::get_template_by_name(&state.db, &name).await?))
}
/// PUT /api/v1/prompts/{name} — 更新模板元数据
pub async fn update_prompt(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(name): Path<String>,
Json(req): Json<UpdatePromptRequest>,
) -> SaasResult<Json<PromptTemplateInfo>> {
check_permission(&ctx, "prompt:write")?;
let tmpl = service::get_template_by_name(&state.db, &name).await?;
let result = service::update_template(
&state.db, &tmpl.id,
req.description.as_deref(),
req.status.as_deref(),
).await?;
log_operation(&state.db, &ctx.account_id, "prompt.update", "prompt", &tmpl.id,
Some(serde_json::json!({"name": name})), ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}
/// DELETE /api/v1/prompts/{name} — 归档模板
pub async fn archive_prompt(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(name): Path<String>,
) -> SaasResult<Json<PromptTemplateInfo>> {
check_permission(&ctx, "prompt:admin")?;
let tmpl = service::get_template_by_name(&state.db, &name).await?;
let result = service::update_template(&state.db, &tmpl.id, None, Some("archived")).await?;
log_operation(&state.db, &ctx.account_id, "prompt.archive", "prompt", &tmpl.id, None, ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}
/// GET /api/v1/prompts/{name}/versions — 查看版本历史
pub async fn list_versions(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(name): Path<String>,
) -> SaasResult<Json<Vec<PromptVersionInfo>>> {
check_permission(&ctx, "prompt:read")?;
let tmpl = service::get_template_by_name(&state.db, &name).await?;
Ok(Json(service::list_versions(&state.db, &tmpl.id).await?))
}
/// GET /api/v1/prompts/{name}/versions/{version} — 获取特定版本
pub async fn get_version(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path((name, _version)): Path<(String, i32)>,
) -> SaasResult<Json<PromptVersionInfo>> {
check_permission(&ctx, "prompt:read")?;
let _tmpl = service::get_template_by_name(&state.db, &name).await?;
Ok(Json(service::get_current_version(&state.db, &name).await?))
}
/// POST /api/v1/prompts/{name}/versions — 发布新版本
pub async fn create_version(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(name): Path<String>,
Json(req): Json<CreateVersionRequest>,
) -> SaasResult<Json<PromptVersionInfo>> {
check_permission(&ctx, "prompt:write")?;
let tmpl = service::get_template_by_name(&state.db, &name).await?;
let result = service::create_version(
&state.db, &tmpl.id,
&req.system_prompt,
req.user_prompt_template.as_deref(),
req.variables.clone(),
req.changelog.as_deref(),
req.min_app_version.as_deref(),
).await?;
log_operation(&state.db, &ctx.account_id, "prompt.publish_version", "prompt", &tmpl.id,
Some(serde_json::json!({"name": name, "version": result.version})), ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}
/// POST /api/v1/prompts/{name}/rollback/{version} — 回退到指定版本
pub async fn rollback_version(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path((name, version)): Path<(String, i32)>,
) -> SaasResult<Json<PromptTemplateInfo>> {
check_permission(&ctx, "prompt:admin")?;
let tmpl = service::get_template_by_name(&state.db, &name).await?;
let result = service::rollback_version(&state.db, &tmpl.id, version).await?;
log_operation(&state.db, &ctx.account_id, "prompt.rollback", "prompt", &tmpl.id,
Some(serde_json::json!({"name": name, "target_version": version})), ctx.client_ip.as_deref()).await?;
Ok(Json(result))
}