fix(aihr): scope knowledge feedback fragments

This commit is contained in:
2026-07-14 10:53:50 +08:00
parent 816bf0e6f5
commit 116fb320c8
4 changed files with 34 additions and 0 deletions
@@ -230,6 +230,7 @@ public class AihrSopSeedService {
if (fragmentIds.isEmpty()) { if (fragmentIds.isEmpty()) {
throw new ServiceException("缺少片段ID"); throw new ServiceException("缺少片段ID");
} }
validateFeedbackFragmentOwnership(fragmentIds);
ensureAnswerFeedbackTable(); ensureAnswerFeedbackTable();
String reviewStatus = "down".equals(verdict) ? "待复核" : "已复核"; String reviewStatus = "down".equals(verdict) ? "待复核" : "已复核";
Timestamp now = Timestamp.valueOf(java.time.LocalDateTime.now()); Timestamp now = Timestamp.valueOf(java.time.LocalDateTime.now());
@@ -2090,6 +2091,24 @@ public class AihrSopSeedService {
return ids.stream().toList(); return ids.stream().toList();
} }
private void validateFeedbackFragmentOwnership(List<Long> fragmentIds) {
if (fragmentIds.size() > 20) {
throw new ServiceException("单次最多反馈 20 个知识片段");
}
String placeholders = String.join(",", fragmentIds.stream().map(id -> "?").toList());
List<Object> args = new ArrayList<>();
args.add(tenantId());
args.addAll(fragmentIds);
List<Long> ownedIds = jdbcTemplate.queryForList("""
SELECT id
FROM aihr_knowledge_fragment
WHERE tenant_id = ? AND id IN (%s)
""".formatted(placeholders), Long.class, args.toArray());
if (ownedIds.size() != fragmentIds.size()) {
throw new ServiceException("知识片段不存在或不属于当前租户");
}
}
private static String formatTimestamp(Timestamp timestamp) { private static String formatTimestamp(Timestamp timestamp) {
return timestamp == null ? "" : timestamp.toLocalDateTime().format(TIME_FORMATTER); return timestamp == null ? "" : timestamp.toLocalDateTime().format(TIME_FORMATTER);
} }
@@ -129,6 +129,19 @@ public class AihrSopSeedServiceTest {
assertTrue(code.contains("reviewAnswerFeedback(id, operator)")); assertTrue(code.contains("reviewAnswerFeedback(id, operator)"));
} }
@Test
@Tag("dev")
public void answerFeedbackValidatesFragmentOwnership() throws Exception {
Path source = Path.of("src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
if (!Files.exists(source)) {
source = Path.of("ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
}
String code = Files.readString(source);
assertTrue(code.contains("validateFeedbackFragmentOwnership(fragmentIds)"));
assertTrue(code.contains("WHERE tenant_id = ? AND id IN (%s)"));
}
private static AihrSopSeedService.KnowledgeHit hit(Long fragmentId, String title) { private static AihrSopSeedService.KnowledgeHit hit(Long fragmentId, String title) {
return new AihrSopSeedService.KnowledgeHit(fragmentId, title, "sop", "", "doc-" + fragmentId, "片段内容", 1, 1.0); return new AihrSopSeedService.KnowledgeHit(fragmentId, title, "sop", "", "doc-" + fragmentId, "片段内容", 1, 1.0);
} }
+1
View File
@@ -180,3 +180,4 @@
- 2026-07-14 BRD 候选人关联完整性复核:候选人—员工关联接口此前只校验员工主体在职,允许给不存在的任意 `candidateId` 建立入职关联;现要求候选人必须来自内置候选档案、活动面试会话或当前租户已持久化面试记录,保留已有幂等关联和历史数据兼容。 - 2026-07-14 BRD 候选人关联完整性复核:候选人—员工关联接口此前只校验员工主体在职,允许给不存在的任意 `candidateId` 建立入职关联;现要求候选人必须来自内置候选档案、活动面试会话或当前租户已持久化面试记录,保留已有幂等关联和历史数据兼容。
- 2026-07-14 BRD SOP 审核留痕复核:SOP 问答评审接口此前接受请求体中的 `reviewer` 并直接入库,登录用户可伪造审核人;现由控制器从当前登录用户传入服务端操作人,请求体仅保留评审结论和备注,保留旧服务调用的默认“人工评审”兼容。 - 2026-07-14 BRD SOP 审核留痕复核:SOP 问答评审接口此前接受请求体中的 `reviewer` 并直接入库,登录用户可伪造审核人;现由控制器从当前登录用户传入服务端操作人,请求体仅保留评审结论和备注,保留旧服务调用的默认“人工评审”兼容。
- 2026-07-14 BRD 知识答案反馈复核:原先只更新 `review_status`,没有复核人和复核时间;现由服务端记录登录操作人到 `reviewer/reviewed_time`,管理端待复核表同步展示留痕。 - 2026-07-14 BRD 知识答案反馈复核:原先只更新 `review_status`,没有复核人和复核时间;现由服务端记录登录操作人到 `reviewer/reviewed_time`,管理端待复核表同步展示留痕。
- 2026-07-14 BRD 知识反馈归属复核:答案反馈原先信任客户端传入的片段 ID,未校验知识片段是否属于当前租户;现入库前按当前租户校验片段归属并限制单次最多 20 个片段。
+1
View File
@@ -495,6 +495,7 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/control
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片文件" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "仅支持 txt/md/markdown/pdf/doc/docx/xls/xlsx/ppt/pptx/图片文件"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "/embeddings" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "/embeddings"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "aihr_knowledge_gap" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "aihr_knowledge_gap"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "validateFeedbackFragmentOwnership"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrVideoService.java "处理输出已隐藏" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrVideoService.java "处理输出已隐藏"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrUploadQueueService.java "资料加工失败,请重试或联系管理员" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrUploadQueueService.java "资料加工失败,请重试或联系管理员"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "目录导入失败,请重试或联系管理员" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "目录导入失败,请重试或联系管理员"