fix(aihr): validate assigned practice starts

This commit is contained in:
2026-07-14 11:27:12 +08:00
parent 347d7b5d5d
commit 516bfabee3
3 changed files with 50 additions and 1 deletions
@@ -473,7 +473,7 @@ public class AihrPracticeSeedService {
}
public StartResponse start(StartRequest request) {
ScenarioSeed scenario = resolveScenario(request == null ? null : request.scenarioId(), null);
ScenarioSeed scenario = resolveScenario(resolveStartScenarioId(request), null);
RoundSeed firstRound = scenario.rounds().get(0);
String sessionId = "seed-" + scenario.id() + "-" + System.currentTimeMillis();
String trainee = resolveTrainee(request, scenario);
@@ -2049,6 +2049,40 @@ public class AihrPracticeSeedService {
return request != null && "mobile".equalsIgnoreCase(request.mode());
}
private String resolveStartScenarioId(StartRequest request) {
String requestedScenarioId = request == null ? "" : firstNonBlank(request.scenarioId(), "").trim();
if (!isMobile(request) || request.assignmentId() == null) {
return requestedScenarioId;
}
String extPartyId = resolveExtPartyId(request, "");
if (isBlank(extPartyId)) {
throw new ServiceException("缺少员工身份,无法开始派发训练");
}
ensureAssignmentTable();
List<Map<String, Object>> rows = jdbcTemplate.queryForList("""
SELECT scenario_id
FROM aihr_practice_assignment
WHERE tenant_id = ?
AND id = ?
AND ext_party_id = ?
AND source <> 'daily'
AND status = '待训练'
LIMIT 1
""", tenantId(), request.assignmentId(), extPartyId.trim());
if (rows.isEmpty()) {
throw new ServiceException("训练任务不存在、已完成或无权访问");
}
Object assignedValue = rows.get(0).get("scenario_id");
String assignedScenarioId = assignedValue == null ? "" : String.valueOf(assignedValue).trim();
if (isBlank(assignedScenarioId)) {
throw new ServiceException("训练任务缺少场景,无法开始");
}
if (!isBlank(requestedScenarioId) && !assignedScenarioId.equals(requestedScenarioId)) {
throw new ServiceException("训练任务场景与请求不一致");
}
return assignedScenarioId;
}
private String resolveExtPartyId(StartRequest request, String trainee) {
if (request == null || isBlank(request.extPartyId())) {
return trainee;
@@ -135,6 +135,20 @@ public class AihrPracticeSeedServiceTest {
assertTrue(method.contains("if (updated == 0)"));
}
@Test
public void mobileAssignmentStartValidatesOwnerStatusAndScenario() throws Exception {
String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java"));
int methodStart = source.indexOf("private String resolveStartScenarioId");
int methodEnd = source.indexOf("private String resolveExtPartyId", methodStart);
assertTrue(methodStart >= 0 && methodEnd > methodStart);
String method = source.substring(methodStart, methodEnd);
assertTrue(method.contains("AND ext_party_id = ?"));
assertTrue(method.contains("AND source <> 'daily'"));
assertTrue(method.contains("AND status = '待训练'"));
assertTrue(method.contains("训练任务场景与请求不一致"));
}
@Test
public void mobilePracticeSessionRejectsForeignAndUnknownOwner() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);