fix(knowledge): verification audit — 3 medium issues
- create_item: wrap item + version INSERT in transaction for atomicity - update_item handler: validate content length (100KB) before DB hit - KnowledgeChunk: document missing embedding field, safe per explicit SELECT usage
This commit is contained in:
@@ -273,6 +273,12 @@ pub async fn update_item(
|
|||||||
) -> SaasResult<Json<serde_json::Value>> {
|
) -> SaasResult<Json<serde_json::Value>> {
|
||||||
check_permission(&ctx, "knowledge:write")?;
|
check_permission(&ctx, "knowledge:write")?;
|
||||||
|
|
||||||
|
if let Some(ref content) = req.content {
|
||||||
|
if content.len() > 100_000 {
|
||||||
|
return Err(SaasError::InvalidInput("内容不能超过 100KB".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let updated = service::update_item(&state.db, &id, &ctx.account_id, &req).await?;
|
let updated = service::update_item(&state.db, &id, &ctx.account_id, &req).await?;
|
||||||
|
|
||||||
// 触发 re-embedding
|
// 触发 re-embedding
|
||||||
|
|||||||
@@ -296,6 +296,9 @@ pub async fn create_item(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 使用事务保证 item + version 原子性
|
||||||
|
let mut tx = pool.begin().await?;
|
||||||
|
|
||||||
let item = sqlx::query_as::<_, KnowledgeItem>(
|
let item = sqlx::query_as::<_, KnowledgeItem>(
|
||||||
"INSERT INTO knowledge_items \
|
"INSERT INTO knowledge_items \
|
||||||
(id, category_id, title, content, keywords, related_questions, priority, tags, created_by) \
|
(id, category_id, title, content, keywords, related_questions, priority, tags, created_by) \
|
||||||
@@ -311,7 +314,7 @@ pub async fn create_item(
|
|||||||
.bind(priority)
|
.bind(priority)
|
||||||
.bind(tags)
|
.bind(tags)
|
||||||
.bind(account_id)
|
.bind(account_id)
|
||||||
.fetch_one(pool)
|
.fetch_one(&mut *tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// 创建初始版本快照
|
// 创建初始版本快照
|
||||||
@@ -328,9 +331,10 @@ pub async fn create_item(
|
|||||||
.bind(keywords)
|
.bind(keywords)
|
||||||
.bind(related_questions)
|
.bind(related_questions)
|
||||||
.bind(account_id)
|
.bind(account_id)
|
||||||
.execute(pool)
|
.execute(&mut *tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ pub struct ItemResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === 知识分块 ===
|
// === 知识分块 ===
|
||||||
|
// 注意:DB 表含 embedding vector(1536) 列,但当前所有查询均显式指定列,
|
||||||
|
// 故 struct 暂不映射该字段。若未来使用 SELECT * 需添加 embedding: Option<pgvector::Vector>。
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||||
pub struct KnowledgeChunk {
|
pub struct KnowledgeChunk {
|
||||||
|
|||||||
Reference in New Issue
Block a user