feat(auth): 添加异步密码哈希和验证函数
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
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
refactor(relay): 复用HTTP客户端和请求体序列化结果 feat(kernel): 添加获取单个审批记录的方法 fix(store): 改进SaaS连接错误分类和降级处理 docs: 更新审计文档和系统架构文档 refactor(prompt): 优化SQL查询参数化绑定 refactor(migration): 使用静态SQL和COALESCE更新配置项 feat(commands): 添加审批执行状态追踪和事件通知 chore: 更新启动脚本以支持Admin后台 fix(auth-guard): 优化授权状态管理和错误处理 refactor(db): 使用异步密码哈希函数 refactor(totp): 使用异步密码验证函数 style: 清理无用文件和注释 docs: 更新功能全景和审计文档 refactor(service): 优化HTTP客户端重用和请求处理 fix(connection): 改进SaaS不可用时的降级处理 refactor(handlers): 使用异步密码验证函数 chore: 更新依赖和工具链配置
This commit is contained in:
@@ -76,62 +76,30 @@ pub async fn get_template_by_name(db: &PgPool, name: &str) -> SaasResult<PromptT
|
||||
}
|
||||
|
||||
/// 列表模板
|
||||
/// Static SQL with conditional filter pattern: ($N IS NULL OR col = $N).
|
||||
pub async fn list_templates(
|
||||
db: &PgPool,
|
||||
query: &PromptListQuery,
|
||||
) -> SaasResult<PaginatedResponse<PromptTemplateInfo>> {
|
||||
let (page, page_size, offset) = normalize_pagination(query.page, query.page_size);
|
||||
|
||||
// 使用参数化查询构建,防止 SQL 注入
|
||||
let mut param_idx = 1usize;
|
||||
let mut conditions = Vec::new();
|
||||
let mut cat_bind: Option<String> = None;
|
||||
let mut src_bind: Option<String> = None;
|
||||
let mut status_bind: Option<String> = None;
|
||||
let count_sql = "SELECT COUNT(*) FROM prompt_templates WHERE ($1 IS NULL OR category = $1) AND ($2 IS NULL OR source = $2) AND ($3 IS NULL OR status = $3)";
|
||||
let data_sql = "SELECT id, name, category, description, source, current_version, status, created_at, updated_at \
|
||||
FROM prompt_templates WHERE ($1 IS NULL OR category = $1) AND ($2 IS NULL OR source = $2) AND ($3 IS NULL OR status = $3) ORDER BY updated_at DESC LIMIT $4 OFFSET $5";
|
||||
|
||||
if let Some(ref cat) = query.category {
|
||||
conditions.push(format!("category = ${}", param_idx));
|
||||
cat_bind = Some(cat.clone());
|
||||
param_idx += 1;
|
||||
}
|
||||
if let Some(ref src) = query.source {
|
||||
conditions.push(format!("source = ${}", param_idx));
|
||||
src_bind = Some(src.clone());
|
||||
param_idx += 1;
|
||||
}
|
||||
if let Some(ref st) = query.status {
|
||||
conditions.push(format!("status = ${}", param_idx));
|
||||
status_bind = Some(st.clone());
|
||||
param_idx += 1;
|
||||
}
|
||||
let total: i64 = sqlx::query_scalar(count_sql)
|
||||
.bind(&query.category)
|
||||
.bind(&query.source)
|
||||
.bind(&query.status)
|
||||
.fetch_one(db).await?;
|
||||
|
||||
let where_clause = if conditions.is_empty() {
|
||||
"1=1".to_string()
|
||||
} else {
|
||||
conditions.join(" AND ")
|
||||
};
|
||||
|
||||
let count_sql = format!("SELECT COUNT(*) FROM prompt_templates WHERE {}", where_clause);
|
||||
let data_sql = format!(
|
||||
"SELECT id, name, category, description, source, current_version, status, created_at, updated_at \
|
||||
FROM prompt_templates WHERE {} ORDER BY updated_at DESC LIMIT {} OFFSET {}",
|
||||
where_clause, page_size, offset
|
||||
);
|
||||
|
||||
// 动态绑定参数到 count 查询
|
||||
let mut count_query = sqlx::query_scalar::<_, i64>(&count_sql);
|
||||
if let Some(ref v) = cat_bind { count_query = count_query.bind(v); }
|
||||
if let Some(ref v) = src_bind { count_query = count_query.bind(v); }
|
||||
if let Some(ref v) = status_bind { count_query = count_query.bind(v); }
|
||||
let total = count_query.fetch_one(db).await?;
|
||||
|
||||
// 动态绑定参数到 data 查询
|
||||
let mut data_query = sqlx::query_as::<_, PromptTemplateRow>(&data_sql);
|
||||
if let Some(ref v) = cat_bind { data_query = data_query.bind(v); }
|
||||
if let Some(ref v) = src_bind { data_query = data_query.bind(v); }
|
||||
if let Some(ref v) = status_bind { data_query = data_query.bind(v); }
|
||||
data_query = data_query.bind(page_size as i64).bind(offset as i64);
|
||||
let rows = data_query.fetch_all(db).await?;
|
||||
let rows: Vec<PromptTemplateRow> = sqlx::query_as(data_sql)
|
||||
.bind(&query.category)
|
||||
.bind(&query.source)
|
||||
.bind(&query.status)
|
||||
.bind(page_size as i64)
|
||||
.bind(offset as i64)
|
||||
.fetch_all(db).await?;
|
||||
|
||||
let items: Vec<PromptTemplateInfo> = rows.into_iter().map(|r| {
|
||||
PromptTemplateInfo { id: r.id, name: r.name, category: r.category, description: r.description, source: r.source, current_version: r.current_version, status: r.status, created_at: r.created_at, updated_at: r.updated_at }
|
||||
|
||||
Reference in New Issue
Block a user