fix(case): restrict mobile case writes
This commit is contained in:
+19
@@ -38,16 +38,25 @@ public class AihrCaseController {
|
||||
|
||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public R<UploadResponse> upload(@RequestPart("file") MultipartFile file, @RequestParam(value = "projectExtOrgId", required = false) String projectExtOrgId) {
|
||||
if (!canManageCases()) {
|
||||
return R.fail("仅项目负责人或主管可提交案例素材");
|
||||
}
|
||||
return R.ok(caseService.upload(file, projectExtOrgId, currentProjectScopes()));
|
||||
}
|
||||
|
||||
@PostMapping("/organize")
|
||||
public R<OrganizeResponse> organize(@RequestBody OrganizeRequest request) {
|
||||
if (!canManageCases()) {
|
||||
return R.fail("仅项目负责人或主管可整理案例素材");
|
||||
}
|
||||
return R.ok(caseService.organize(request, currentProjectScopes()));
|
||||
}
|
||||
|
||||
@PostMapping("/curate")
|
||||
public R<CurateResponse> curate(@RequestBody CurateRequest request) {
|
||||
if (!canManageCases()) {
|
||||
return R.fail("仅项目负责人或主管可入库案例");
|
||||
}
|
||||
return R.ok(caseService.curate(request, currentProjectScopes()));
|
||||
}
|
||||
|
||||
@@ -72,4 +81,14 @@ public class AihrCaseController {
|
||||
}
|
||||
return caseService.projectScopesForAppUser(loginUser.getUsername());
|
||||
}
|
||||
|
||||
private boolean canManageCases() {
|
||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
if (loginUser != null && UserType.SYS_USER.getUserType().equals(loginUser.getUserType())) {
|
||||
return true;
|
||||
}
|
||||
return loginUser != null
|
||||
&& UserType.APP_USER.getUserType().equals(loginUser.getUserType())
|
||||
&& caseService.isCaseContributor(loginUser.getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
+32
@@ -181,6 +181,31 @@ public class AihrCaseService {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCaseContributor(String identity) {
|
||||
String username = clean(identity);
|
||||
if (username.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Integer count = jdbcTemplate.queryForObject("""
|
||||
SELECT COUNT(*)
|
||||
FROM aihr_org_snapshot
|
||||
WHERE tenant_id = '000000'
|
||||
AND employment_status = 'active'
|
||||
AND (person_phone = ? OR ext_party_id = ?)
|
||||
AND (position_level IN ('主管', '项目经理')
|
||||
OR position_name LIKE '%主管%'
|
||||
OR position_name LIKE '%经理%'
|
||||
OR position_name LIKE '%负责人%'
|
||||
OR position_name LIKE '%组长%')
|
||||
""", Integer.class, username, username);
|
||||
return count != null && count > 0;
|
||||
} catch (DataAccessException e) {
|
||||
log.warn("resolve case contributor failed: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCase(CaseState state, String status, String title, String summary) {
|
||||
ensureCaseTable();
|
||||
jdbcTemplate.update("""
|
||||
@@ -305,6 +330,13 @@ public class AihrCaseService {
|
||||
|| (!projectScopes.isEmpty() && projectScopes.contains(clean(projectExtOrgId)));
|
||||
}
|
||||
|
||||
static boolean isCaseContributorPosition(String positionName, String positionLevel) {
|
||||
String name = clean(positionName);
|
||||
String level = clean(positionLevel);
|
||||
return "主管".equals(level) || "项目经理".equals(level)
|
||||
|| name.contains("主管") || name.contains("经理") || name.contains("负责人") || name.contains("组长");
|
||||
}
|
||||
|
||||
private String resolveUploadProject(String requestedProject, List<String> projectScopes) {
|
||||
if (projectScopes == null) {
|
||||
return firstNonBlank(requestedProject, "");
|
||||
|
||||
+10
@@ -82,6 +82,16 @@ class AihrCaseServiceTest {
|
||||
assertTrue(AihrCaseService.caseProjectAllowed("P1", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("dev")
|
||||
void caseContributorPositionRecognizesProjectManagersAndLeads() {
|
||||
assertTrue(AihrCaseService.isCaseContributorPosition("项目经理", "一线"));
|
||||
assertTrue(AihrCaseService.isCaseContributorPosition("招商主管", "一线"));
|
||||
assertTrue(AihrCaseService.isCaseContributorPosition("项目负责人", "一线"));
|
||||
assertTrue(AihrCaseService.isCaseContributorPosition("普通员工", "主管"));
|
||||
assertFalse(AihrCaseService.isCaseContributorPosition("普通员工", "一线"));
|
||||
}
|
||||
|
||||
private static class CaseJdbcTemplate extends JdbcTemplate {
|
||||
private Object[] updateArgs = new Object[0];
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
| 候选人面试与 HR 复核 | `mobile-uni/src/pages/candidate/*`、`frontend/src/views/recruit/interview.vue` | 工程闭环已在位,需继续保留人工复核证据 |
|
||||
| SOP/RAG/资料处理 | `frontend/src/views/knowledge/*`、`backend/.../AihrSopSeedService.java` | 搜索、引用、反馈、异步处理和评审入口已在位 |
|
||||
| 对练/每日题/主管带教 | `backend/.../AihrPracticeSeedService.java`、`mobile-uni/src/pages/user/practice` | 主闭环已在位;低分再练、错题归因仍需更明确的用户可见闭环 |
|
||||
| 案例上传/整理/筛选 | `backend/.../AihrCaseService.java`、`mobile-uni/src/pages/user/cases`、`frontend/src/views/knowledge/cases.vue` | 上传与整理已在位,案例状态在内存缺失时可从 `aihr_case_record` 回读恢复;APP 用户的上传、整理、入库和列表现在按 `aihr_org_snapshot` 项目范围校验,缺少正式组织映射时拒绝访问;当前仓库仍没有可用预渲染视频样片资产,也没有稳定的案例详情/学习点模型,不能用假播放器宣称案例学习闭环完成 |
|
||||
| 案例上传/整理/筛选 | `backend/.../AihrCaseService.java`、`mobile-uni/src/pages/user/cases`、`frontend/src/views/knowledge/cases.vue` | 上传与整理已在位,案例状态在内存缺失时可从 `aihr_case_record` 回读恢复;APP 用户的读取按项目范围校验,写入接口已增加“主管/项目经理/系统用户”门禁,普通员工不能提交、整理或入库案例;当前仓库仍没有可用预渲染视频样片资产,也没有稳定的案例详情/学习点模型,不能用假播放器宣称案例学习闭环完成 |
|
||||
|
||||
## 3. 未完成项与优先级
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</button>
|
||||
<view class="subpage-heading">
|
||||
<text class="page-title">案例素材</text>
|
||||
<text class="page-subtitle">把一线语音整理成可复用培训案例。上传后依次完成 ASR、AI 整理和入库。</text>
|
||||
<text class="page-subtitle">项目负责人或主管可把一线语音整理成培训案例;其他员工可查看本项目已入库案例。</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -428,6 +428,8 @@ 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 "/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/controller/AihrCaseController.java "仅项目负责人或主管可提交案例素材"
|
||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrCaseService.java "position_level IN ('主管', '项目经理')"
|
||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "prompt_version"
|
||||
contains backend/script/sql/aihr_practice_mysql8.sql "prompt_version"
|
||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "review_id"
|
||||
|
||||
Reference in New Issue
Block a user