174 lines
6.1 KiB
Rust
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))
|
|
}
|