Compare commits

...

3 Commits

Author SHA1 Message Date
chenyuan 61b3c169a9 fix: 考试分析-最难题目SQL在不选班级时缺少空格导致语法错误,点分析报错 5 days ago
chenyuan 8d7a4fdaab test: 测试代码改用JDK8兼容写法(List.of/String.repeat),可在JDK8下编译运行 5 days ago
chenyuan 78bb701e53 fix: 教师可选用本校题库题目组卷;简答题资料支持Excel;未发布考试可删除
- 保存/发布考试时题目校验放宽为:平台题、自己的题、本校教师的题,
  与选题列表(scope=school)口径一致,修复"题目不存在或无权访问"
- 简答题题目资料(教师端/平台管理端)新增 xls、xlsx,学生作答文件规则不变
- 未发布(DRAFT)的考试允许直接删除,其余状态规则不变
5 days ago

@ -52,6 +52,7 @@ public class ExamService {
private static final Set<String> MULTIPLE_SCORE_MODES = new HashSet<>(Arrays.asList(ALL_OR_NOTHING, PARTIAL_BY_COUNT, HALF_FOR_PARTIAL)); private static final Set<String> MULTIPLE_SCORE_MODES = new HashSet<>(Arrays.asList(ALL_OR_NOTHING, PARTIAL_BY_COUNT, HALF_FOR_PARTIAL));
private static final Set<String> TYPES = new LinkedHashSet<>(Arrays.asList(SINGLE, MULTIPLE, TRUE_FALSE, SHORT_ANSWER)); private static final Set<String> TYPES = new LinkedHashSet<>(Arrays.asList(SINGLE, MULTIPLE, TRUE_FALSE, SHORT_ANSWER));
private static final Set<String> ALLOWED_ATTACHMENTS = new HashSet<>(Arrays.asList("pdf", "doc", "docx", "png", "jpg", "jpeg")); private static final Set<String> ALLOWED_ATTACHMENTS = new HashSet<>(Arrays.asList("pdf", "doc", "docx", "png", "jpg", "jpeg"));
private static final Set<String> ALLOWED_MATERIALS = new HashSet<>(Arrays.asList("pdf", "doc", "docx", "xls", "xlsx", "png", "jpg", "jpeg"));
private static final long MAX_ATTACHMENT_SIZE = 20L * 1024 * 1024; private static final long MAX_ATTACHMENT_SIZE = 20L * 1024 * 1024;
private static final DateTimeFormatter TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final Pattern OPTION_LINE = Pattern.compile("^([A-Ha-h])\\s*[..、::]\\s*(.+)$"); private static final Pattern OPTION_LINE = Pattern.compile("^([A-Ha-h])\\s*[..、::]\\s*(.+)$");
@ -133,7 +134,7 @@ public class ExamService {
public Map<String, Object> uploadQuestionAttachment(JwtUser teacher, MultipartFile file) { public Map<String, Object> uploadQuestionAttachment(JwtUser teacher, MultipartFile file) {
requireTeacher(teacher); requireTeacher(teacher);
validateAttachment(file); validateMaterial(file);
String path = fileUtil.upload(file); String path = fileUtil.upload(file);
return map("name", safeFilename(file.getOriginalFilename()), "url", "/" + path.replace('\\', '/')); return map("name", safeFilename(file.getOriginalFilename()), "url", "/" + path.replace('\\', '/'));
} }
@ -310,7 +311,7 @@ public class ExamService {
int order = 1; int order = 1;
for (Map<String, Object> item : paper) { for (Map<String, Object> item : paper) {
long questionId = number(item.get("questionId")).longValue(); long questionId = number(item.get("questionId")).longValue();
Map<String, Object> question = getOwnedQuestion(teacher, questionId); Map<String, Object> question = getUsableQuestion(teacher, questionId);
jdbc.update("insert into exam_assessment_question(exam_id,question_id,question_order,question_score,question_type,stem,options_json,answer_json,answer_analysis,attachment_name,attachment_url) values(?,?,?,?,?,?,?,?,?,?,?)", jdbc.update("insert into exam_assessment_question(exam_id,question_id,question_order,question_score,question_type,stem,options_json,answer_json,answer_analysis,attachment_name,attachment_url) values(?,?,?,?,?,?,?,?,?,?,?)",
examId, questionId, order++, decimal(item.get("score")), question.get("type"), question.get("stem"), json(question.get("options")), examId, questionId, order++, decimal(item.get("score")), question.get("type"), question.get("stem"), json(question.get("options")),
json(question.get("answer")), question.get("analysis"), question.get("attachmentName"), question.get("attachmentUrl")); json(question.get("answer")), question.get("analysis"), question.get("attachmentName"), question.get("attachmentUrl"));
@ -432,14 +433,7 @@ public class ExamService {
bucket("良好", scores, total.multiply(new BigDecimal("0.80")), total.multiply(new BigDecimal("0.90"))), bucket("良好", scores, total.multiply(new BigDecimal("0.80")), total.multiply(new BigDecimal("0.90"))),
bucket("及格", scores, pass, total.multiply(new BigDecimal("0.80"))), bucket("及格", scores, pass, total.multiply(new BigDecimal("0.80"))),
bucket("不及格", scores, BigDecimal.ZERO, pass)); bucket("不及格", scores, BigDecimal.ZERO, pass));
String hardestSql = "select p.question_id id,p.stem,p.question_score, count(distinct t.id) student_count, " + String hardestSql = analysisHardestSql(StringUtils.isNotBlank(classId));
"sum(case when coalesce(a.awarded_score,0) < p.question_score then 1 else 0 end) wrong_count, " +
"coalesce(sum(coalesce(a.awarded_score,0)),0) earned_score " +
"from exam_assessment_question p join exam_attempt t on t.exam_id=p.exam_id and t.attempt_status='SUBMITTED' " +
"left join exam_attempt_answer a on a.attempt_id=t.id and a.question_id=p.question_id " +
"where p.exam_id=?" + (StringUtils.isBlank(classId) ? "" : " and t.teaching_class_id=? ") +
"group by p.question_id,p.stem,p.question_score " +
"order by (case when count(distinct t.id)=0 then 100 else coalesce(sum(coalesce(a.awarded_score,0)),0) * 100.0 / (count(distinct t.id) * p.question_score) end) asc, wrong_count desc limit 3";
List<Map<String, Object>> hardest = jdbc.query(hardestSql, List<Map<String, Object>> hardest = jdbc.query(hardestSql,
(rs, n) -> { (rs, n) -> {
int students = rs.getInt("student_count"); int students = rs.getInt("student_count");
@ -676,6 +670,13 @@ public class ExamService {
return rows.get(0); return rows.get(0);
} }
private Map<String, Object> getUsableQuestion(JwtUser teacher, long id) {
String schoolId = teacher.getSchoolId();
List<Map<String, Object>> rows = jdbc.query("select q.*,t.project_name,t.task_name from exam_question q left join training_task t on t.task_key=q.task_key where q.id=? and (q.source_type='PLATFORM' or (q.source_type='TEACHER' and (q.teacher_id=? or (? is not null and q.school_id=?))))", (rs, n) -> questionRow(rs, true), id, teacher.getUserId(), schoolId, schoolId);
if (rows.isEmpty()) throw new IllegalArgumentException("题目不存在或无权访问");
return rows.get(0);
}
private Map<String, Object> ownedExam(JwtUser teacher, long id) { private Map<String, Object> ownedExam(JwtUser teacher, long id) {
requireTeacher(teacher); requireTeacher(teacher);
List<Map<String, Object>> rows = jdbc.query("select e.*,(select coalesce(sum(question_score),0) from exam_assessment_question q where q.exam_id=e.id) total_score from exam_assessment e where e.id=? and e.teacher_id=?", List<Map<String, Object>> rows = jdbc.query("select e.*,(select coalesce(sum(question_score),0) from exam_assessment_question q where q.exam_id=e.id) total_score from exam_assessment e where e.id=? and e.teacher_id=?",
@ -746,8 +747,20 @@ public class ExamService {
if (!expected.equals(actual)) throw new IllegalArgumentException(message); if (!expected.equals(actual)) throw new IllegalArgumentException(message);
} }
static String analysisHardestSql(boolean withClassFilter) {
return "select p.question_id id,p.stem,p.question_score, count(distinct t.id) student_count, " +
"sum(case when coalesce(a.awarded_score,0) < p.question_score then 1 else 0 end) wrong_count, " +
"coalesce(sum(coalesce(a.awarded_score,0)),0) earned_score " +
"from exam_assessment_question p join exam_attempt t on t.exam_id=p.exam_id and t.attempt_status='SUBMITTED' " +
"left join exam_attempt_answer a on a.attempt_id=t.id and a.question_id=p.question_id " +
"where p.exam_id=? " + (withClassFilter ? "and t.teaching_class_id=? " : "") +
"group by p.question_id,p.stem,p.question_score " +
"order by (case when count(distinct t.id)=0 then 100 else coalesce(sum(coalesce(a.awarded_score,0)),0) * 100.0 / (count(distinct t.id) * p.question_score) end) asc, wrong_count desc limit 3";
}
static void validateDelete(String status, Object exportedAt) { static void validateDelete(String status, Object exportedAt) {
requireState(status, "ENDED", "只有已结束考试可以删除"); if ("DRAFT".equals(status)) return;
requireState(status, "ENDED", "只有未发布或已结束的考试可以删除");
if (exportedAt == null) throw new IllegalArgumentException("请先导出全部试卷后再删除考试"); if (exportedAt == null) throw new IllegalArgumentException("请先导出全部试卷后再删除考试");
} }
@ -800,7 +813,7 @@ public class ExamService {
for (Map<String, Object> item : paper) { for (Map<String, Object> item : paper) {
long id = number(item.get("questionId")).longValue(); long id = number(item.get("questionId")).longValue();
if (!seen.add(id)) throw new IllegalArgumentException("试卷中存在重复题目"); if (!seen.add(id)) throw new IllegalArgumentException("试卷中存在重复题目");
getOwnedQuestion(teacher, id); getUsableQuestion(teacher, id);
if (decimal(item.get("score")).signum() <= 0) throw new IllegalArgumentException("每题分值必须大于0"); if (decimal(item.get("score")).signum() <= 0) throw new IllegalArgumentException("每题分值必须大于0");
} }
} }
@ -1188,7 +1201,9 @@ public class ExamService {
if (!Arrays.asList("docx", "xls", "xlsx").contains(extension)) throw new IllegalArgumentException("仅支持docx、xls或xlsx格式"); if (!Arrays.asList("docx", "xls", "xlsx").contains(extension)) throw new IllegalArgumentException("仅支持docx、xls或xlsx格式");
return extension; return extension;
} }
private static void validateAttachment(MultipartFile file) { if (file == null || file.isEmpty()) throw new IllegalArgumentException("请选择附件"); if (file.getSize() > MAX_ATTACHMENT_SIZE) throw new IllegalArgumentException("附件不能超过20MB"); String n = safeFilename(file.getOriginalFilename()); int i = n.lastIndexOf('.'); if (i < 0 || !ALLOWED_ATTACHMENTS.contains(n.substring(i + 1).toLowerCase())) throw new IllegalArgumentException("附件仅支持PDF、Word和图片格式"); } private static void validateAttachment(MultipartFile file) { validateAttachment(file, ALLOWED_ATTACHMENTS, "附件仅支持PDF、Word和图片格式"); }
private static void validateMaterial(MultipartFile file) { validateAttachment(file, ALLOWED_MATERIALS, "题目资料仅支持PDF、Word、Excel和图片格式"); }
private static void validateAttachment(MultipartFile file, Set<String> allowed, String unsupportedMessage) { if (file == null || file.isEmpty()) throw new IllegalArgumentException("请选择附件"); if (file.getSize() > MAX_ATTACHMENT_SIZE) throw new IllegalArgumentException("附件不能超过20MB"); String n = safeFilename(file.getOriginalFilename()); int i = n.lastIndexOf('.'); if (i < 0 || !allowed.contains(n.substring(i + 1).toLowerCase())) throw new IllegalArgumentException(unsupportedMessage); }
private static String safeFilename(String name) { return StringUtils.defaultString(name).replace("\\", "_").replace("/", "_"); } private static String safeFilename(String name) { return StringUtils.defaultString(name).replace("\\", "_").replace("/", "_"); }
private static void requireTeacher(JwtUser user) { if (user == null) throw new AccessDeniedException("请先登录"); if (user.getRoleId() != 3) throw new AccessDeniedException("仅教师可以操作"); } private static void requireTeacher(JwtUser user) { if (user == null) throw new AccessDeniedException("请先登录"); if (user.getRoleId() != 3) throw new AccessDeniedException("仅教师可以操作"); }
private static void requireStudent(JwtUser user) { if (user == null) throw new AccessDeniedException("请先登录"); if (user.getRoleId() != 4) throw new AccessDeniedException("仅学生可以操作"); } private static void requireStudent(JwtUser user) { if (user == null) throw new AccessDeniedException("请先登录"); if (user.getRoleId() != 4) throw new AccessDeniedException("仅学生可以操作"); }

@ -41,7 +41,7 @@ public class PlatformQuestionBankService {
if (file.getSize() > 20L * 1024 * 1024) throw new IllegalArgumentException("资料不能超过20MB"); if (file.getSize() > 20L * 1024 * 1024) throw new IllegalArgumentException("资料不能超过20MB");
String name = StringUtils.defaultString(file.getOriginalFilename()).replace("\\", "_").replace("/", "_"); String name = StringUtils.defaultString(file.getOriginalFilename()).replace("\\", "_").replace("/", "_");
int dot = name.lastIndexOf('.'); String ext = dot < 0 ? "" : name.substring(dot + 1).toLowerCase(Locale.ROOT); int dot = name.lastIndexOf('.'); String ext = dot < 0 ? "" : name.substring(dot + 1).toLowerCase(Locale.ROOT);
if (!Arrays.asList("pdf", "doc", "docx", "png", "jpg", "jpeg").contains(ext)) throw new IllegalArgumentException("资料仅支持PDF、Word和图片格式"); if (!Arrays.asList("pdf", "doc", "docx", "xls", "xlsx", "png", "jpg", "jpeg").contains(ext)) throw new IllegalArgumentException("资料仅支持PDF、Word、Excel和图片格式");
String path = fileUtil.upload(file); String path = fileUtil.upload(file);
return map("name", name, "url", "/" + path.replace('\\', '/')); return map("name", name, "url", "/" + path.replace('\\', '/'));
} }

@ -34,7 +34,7 @@ class SchoolDefaultTaskControllerTest {
ready.setStatus("READY"); ready.setStatus("READY");
when(service.getInitialization("school-1")).thenReturn(ready); when(service.getInitialization("school-1")).thenReturn(ready);
controller.replace(List.of(task("学校默认任务")), requestFor("teacher-1", "school-1")); controller.replace(java.util.Arrays.asList(task("学校默认任务")), requestFor("teacher-1", "school-1"));
verify(service).replaceSchoolDefault(eq("school-1"), anyList()); verify(service).replaceSchoolDefault(eq("school-1"), anyList());
} }
@ -47,7 +47,7 @@ class SchoolDefaultTaskControllerTest {
when(userinfoMapper.selectByPrimaryKey("teacher-2")).thenReturn(teacher("teacher-2", "school-1", false)); when(userinfoMapper.selectByPrimaryKey("teacher-2")).thenReturn(teacher("teacher-2", "school-1", false));
assertThrows(UnAuthorizedException.class, assertThrows(UnAuthorizedException.class,
() -> controller.replace(List.of(task("学校默认任务")), requestFor("teacher-2", "school-1"))); () -> controller.replace(java.util.Arrays.asList(task("学校默认任务")), requestFor("teacher-2", "school-1")));
} }
private Userinfo teacher(String userId, String schoolId, boolean teacherAdmin) { private Userinfo teacher(String userId, String schoolId, boolean teacherAdmin) {

@ -91,11 +91,11 @@ class TaskAllocationControllerTest {
ReflectionTestUtils.setField(controller, "schoolDefaultTaskService", defaultTaskService); ReflectionTestUtils.setField(controller, "schoolDefaultTaskService", defaultTaskService);
TaskAllocation allocation = new TaskAllocation(); TaskAllocation allocation = new TaskAllocation();
allocation.setModule("学校默认任务"); allocation.setModule("学校默认任务");
when(defaultTaskService.resolveForTeachingClass("teaching-1")).thenReturn(List.of(allocation)); when(defaultTaskService.resolveForTeachingClass("teaching-1")).thenReturn(java.util.Arrays.asList(allocation));
ResultEntity<List<TaskAllocation>> result = controller.selectTaskAllocationByClassId("teaching-1"); ResultEntity<List<TaskAllocation>> result = controller.selectTaskAllocationByClassId("teaching-1");
assertEquals(List.of(allocation), result.getBody().getData()); assertEquals(java.util.Arrays.asList(allocation), result.getBody().getData());
} }
private TaskAllocationController controllerWithMocks() { private TaskAllocationController controllerWithMocks() {

@ -41,6 +41,39 @@ class ExamServiceTest {
private final JdbcTemplate jdbc = mock(JdbcTemplate.class); private final JdbcTemplate jdbc = mock(JdbcTemplate.class);
private final ExamService service = new ExamService(jdbc, new ObjectMapper(), mock(IFileUtil.class)); private final ExamService service = new ExamService(jdbc, new ObjectMapper(), mock(IFileUtil.class));
@Test
void questionMaterialAcceptsWordAndExcelButRejectsOtherTypes() {
IFileUtil fileUtil = mock(IFileUtil.class);
when(fileUtil.upload(any(org.springframework.web.multipart.MultipartFile.class))).thenReturn("exam/material");
ExamService uploadService = new ExamService(jdbc, new ObjectMapper(), fileUtil);
for (String name : Arrays.asList("资料.doc", "资料.docx", "数据.xls", "数据.XLSX", "说明.pdf", "图.png")) {
Map<String, Object> result = uploadService.uploadQuestionAttachment(teacher(), new MockMultipartFile("file", name, "application/octet-stream", new byte[]{1}));
assertEquals(name, result.get("name"));
}
for (String name : Arrays.asList("脚本.exe", "数据.csv", "无扩展名")) {
IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
() -> uploadService.uploadQuestionAttachment(teacher(), new MockMultipartFile("file", name, "application/octet-stream", new byte[]{1})));
assertEquals("题目资料仅支持PDF、Word、Excel和图片格式", error.getMessage());
}
}
@Test
void analysisHardestSqlKeepsParameterAndGroupBySeparated() {
for (String sql : Arrays.asList(ExamService.analysisHardestSql(false), ExamService.analysisHardestSql(true))) {
assertFalse(sql.contains("?group"));
assertTrue(sql.contains("? group by p.question_id"));
}
assertTrue(ExamService.analysisHardestSql(true).contains("? and t.teaching_class_id=? group by"));
}
@Test
void studentAnswerFilesStillRejectExcel() {
IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
() -> service.uploadAnswerFile(student(), 1L, 1L, "device", new MockMultipartFile("file", "答案.xlsx", "application/octet-stream", new byte[]{1})));
assertEquals("附件仅支持PDF、Word和图片格式", error.getMessage());
}
@Test @Test
void recognizesOnlyCompletePlainOrBracketedQuestionTypeMarkers() { void recognizesOnlyCompletePlainOrBracketedQuestionTypeMarkers() {
assertEquals(ExamService.SINGLE, ExamService.typeMarker("[单选题]")); assertEquals(ExamService.SINGLE, ExamService.typeMarker("[单选题]"));
@ -202,6 +235,9 @@ class ExamServiceTest {
assertThrows(IllegalArgumentException.class, () -> ExamService.requireState("IN_PROGRESS", "NOT_STARTED", "error")); assertThrows(IllegalArgumentException.class, () -> ExamService.requireState("IN_PROGRESS", "NOT_STARTED", "error"));
assertThrows(IllegalArgumentException.class, () -> ExamService.validateDelete("IN_PROGRESS", new Object())); assertThrows(IllegalArgumentException.class, () -> ExamService.validateDelete("IN_PROGRESS", new Object()));
assertThrows(IllegalArgumentException.class, () -> ExamService.validateDelete("ENDED", null)); assertThrows(IllegalArgumentException.class, () -> ExamService.validateDelete("ENDED", null));
assertThrows(IllegalArgumentException.class, () -> ExamService.validateDelete("NOT_STARTED", new Object()));
ExamService.validateDelete("DRAFT", null);
ExamService.validateDelete("ENDED", new Object());
} }
@Test @Test

@ -310,7 +310,7 @@ class AiTrainingEvaluationServiceImplTest {
void assessmentLimitsAllStepRationalesToTwoHundredCharacters() throws Exception { void assessmentLimitsAllStepRationalesToTwoHundredCharacters() throws Exception {
AiTrainingEvaluationServiceImpl service = serviceWithContext(answer("answer-1", "step one", null, null, null)); AiTrainingEvaluationServiceImpl service = serviceWithContext(answer("answer-1", "step one", null, null, null));
AiTrainingEvaluation evaluation = evaluation("NOT_STARTED", "NOT_STARTED"); AiTrainingEvaluation evaluation = evaluation("NOT_STARTED", "NOT_STARTED");
String longRationale = "评分依据".repeat(80); String longRationale = String.join("", java.util.Collections.nCopies(80, "评分依据"));
String response = assessmentJson() String response = assessmentJson()
.replace("evidence", longRationale) .replace("evidence", longRationale)
.replace("logic", longRationale) .replace("logic", longRationale)
@ -340,7 +340,7 @@ class AiTrainingEvaluationServiceImplTest {
void assessmentTruncationUsesASentenceBoundaryWhenAvailable() throws Exception { void assessmentTruncationUsesASentenceBoundaryWhenAvailable() throws Exception {
AiTrainingEvaluationServiceImpl service = serviceWithContext(answer("answer-1", "step one", null, null, null)); AiTrainingEvaluationServiceImpl service = serviceWithContext(answer("answer-1", "step one", null, null, null));
AiTrainingEvaluation evaluation = evaluation("NOT_STARTED", "NOT_STARTED"); AiTrainingEvaluation evaluation = evaluation("NOT_STARTED", "NOT_STARTED");
String response = assessmentJson().replace("evidence", "第一句说明问题。第二句非常长" + "内容".repeat(80)); String response = assessmentJson().replace("evidence", "第一句说明问题。第二句非常长" + String.join("", java.util.Collections.nCopies(80, "内容")));
when(service.aiTrainingEvaluationMapper.findByStudentClassAndTask("stu-1", "class-1", "task-1")) when(service.aiTrainingEvaluationMapper.findByStudentClassAndTask("stu-1", "class-1", "task-1"))
.thenReturn(null, evaluation); .thenReturn(null, evaluation);
when(service.aiTrainingEvaluationMapper.claimAssessment(eq("evaluation-1"), any(Date.class))).thenReturn(1); when(service.aiTrainingEvaluationMapper.claimAssessment(eq("evaluation-1"), any(Date.class))).thenReturn(1);

@ -32,11 +32,11 @@ class SchoolDefaultTaskServiceImplTest {
schoolClass.setClassType("TEACHING"); schoolClass.setClassType("TEACHING");
when(classMapper.selectByPrimaryKey("class-1")).thenReturn(schoolClass); when(classMapper.selectByPrimaryKey("class-1")).thenReturn(schoolClass);
when(taskMapper.selectByExample(any())).thenReturn( when(taskMapper.selectByExample(any())).thenReturn(
Collections.emptyList(), List.of(task("学校默认任务")), List.of(task("平台默认任务"))); Collections.emptyList(), java.util.Arrays.asList(task("学校默认任务")), java.util.Arrays.asList(task("平台默认任务")));
List<TaskAllocation> result = service.resolveForTeachingClass("class-1"); List<TaskAllocation> result = service.resolveForTeachingClass("class-1");
assertEquals(List.of("学校默认任务"), result.stream().map(TaskAllocation::getModule).collect(java.util.stream.Collectors.toList())); assertEquals(java.util.Arrays.asList("学校默认任务"), result.stream().map(TaskAllocation::getModule).collect(java.util.stream.Collectors.toList()));
verify(taskMapper, never()).insert(any()); verify(taskMapper, never()).insert(any());
} }

@ -67,8 +67,8 @@ class TrainingTaskServiceImplTest {
TrainingTaskClassConfig teacherConfig = overrideTask("config-1", "class-1", "new-product-survey"); TrainingTaskClassConfig teacherConfig = overrideTask("config-1", "class-1", "new-product-survey");
teacherConfig.setMaterialName("教师案例.docx"); teacherConfig.setMaterialName("教师案例.docx");
teacherConfig.setMaterialUrl("/file/teacher-case.docx"); teacherConfig.setMaterialUrl("/file/teacher-case.docx");
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(task)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(task));
when(service.trainingTaskClassConfigMapper.selectAll()).thenReturn(List.of(teacherConfig)); when(service.trainingTaskClassConfigMapper.selectAll()).thenReturn(java.util.Arrays.asList(teacherConfig));
int indexed = service.reindexCaseMaterials(); int indexed = service.reindexCaseMaterials();
@ -205,7 +205,7 @@ class TrainingTaskServiceImplTest {
SchoolClass defaultClass = teachingClass("class-default", "teacher-1"); SchoolClass defaultClass = teachingClass("class-default", "teacher-1");
SchoolClass customizedClass = teachingClass("class-customized", "teacher-2"); SchoolClass customizedClass = teachingClass("class-customized", "teacher-2");
when(service.schoolClassMapper.selectByExample(any())).thenReturn(List.of(defaultClass, customizedClass)); when(service.schoolClassMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(defaultClass, customizedClass));
TrainingTaskClassConfig defaultConfig = overrideTask("config-default", "class-default", "new-product-survey"); TrainingTaskClassConfig defaultConfig = overrideTask("config-default", "class-default", "new-product-survey");
defaultConfig.setTaskName("Original Name"); defaultConfig.setTaskName("Original Name");
@ -750,15 +750,15 @@ class TrainingTaskServiceImplTest {
TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTaskServiceImpl service = studentTaskService("class-1");
TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask legacy = storedTask("task-1", "new-product-survey");
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(legacy, comprehensive));
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null))
.thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), .thenReturn(java.util.Arrays.asList(overrideTask("config-1", "class-1", "new-product-survey"),
overrideTask("config-2", "class-1", "comprehensive-case-training"))); overrideTask("config-2", "class-1", "comprehensive-case-training")));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList()); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList());
List<TrainingTask> result = service.listForStudent("stu-1", true); List<TrainingTask> result = service.listForStudent("stu-1", true);
assertEquals(List.of("new-product-survey"), result.stream() assertEquals(java.util.Arrays.asList("new-product-survey"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }
@ -782,7 +782,7 @@ class TrainingTaskServiceImplTest {
when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive);
when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training"))
.thenReturn(overrideTask("config-1", "class-1", "comprehensive-case-training")); .thenReturn(overrideTask("config-1", "class-1", "comprehensive-case-training"));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("comprehensive-case-training", (byte) 0))); taskAllocation("comprehensive-case-training", (byte) 0)));
@ -800,7 +800,7 @@ class TrainingTaskServiceImplTest {
disabled.setEnabled(Boolean.FALSE); disabled.setEnabled(Boolean.FALSE);
when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training"))
.thenReturn(disabled); .thenReturn(disabled);
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("comprehensive-case-training", (byte) 0))); taskAllocation("comprehensive-case-training", (byte) 0)));
@ -814,18 +814,18 @@ class TrainingTaskServiceImplTest {
TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTaskServiceImpl service = studentTaskService("class-1");
TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask legacy = storedTask("task-1", "new-product-survey");
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(legacy, comprehensive));
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null))
.thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), .thenReturn(java.util.Arrays.asList(overrideTask("config-1", "class-1", "new-product-survey"),
overrideTask("config-2", "class-1", "comprehensive-case-training"))); overrideTask("config-2", "class-1", "comprehensive-case-training")));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("new-product-survey", (byte) 0), taskAllocation("new-product-survey", (byte) 0),
taskAllocation("comprehensive-case-training", (byte) 0))); taskAllocation("comprehensive-case-training", (byte) 0)));
List<TrainingTask> result = service.listForStudent("stu-1", true); List<TrainingTask> result = service.listForStudent("stu-1", true);
assertEquals(List.of("new-product-survey", "comprehensive-case-training"), result.stream() assertEquals(java.util.Arrays.asList("new-product-survey", "comprehensive-case-training"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }
@ -835,17 +835,17 @@ class TrainingTaskServiceImplTest {
TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTaskServiceImpl service = studentTaskService("class-1");
TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask legacy = storedTask("task-1", "new-product-survey");
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(legacy, comprehensive));
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null))
.thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), .thenReturn(java.util.Arrays.asList(overrideTask("config-1", "class-1", "new-product-survey"),
overrideTask("config-2", "class-1", "comprehensive-case-training"))); overrideTask("config-2", "class-1", "comprehensive-case-training")));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("new-product-survey", (byte) 0))); taskAllocation("new-product-survey", (byte) 0)));
List<TrainingTask> result = service.listForStudent("stu-1", true); List<TrainingTask> result = service.listForStudent("stu-1", true);
assertEquals(List.of("new-product-survey"), result.stream() assertEquals(java.util.Arrays.asList("new-product-survey"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }
@ -855,18 +855,18 @@ class TrainingTaskServiceImplTest {
TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTaskServiceImpl service = studentTaskService("class-1");
TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask legacy = storedTask("task-1", "new-product-survey");
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(legacy, comprehensive));
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null))
.thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), .thenReturn(java.util.Arrays.asList(overrideTask("config-1", "class-1", "new-product-survey"),
overrideTask("config-2", "class-1", "comprehensive-case-training"))); overrideTask("config-2", "class-1", "comprehensive-case-training")));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("new-product-survey", (byte) 0), taskAllocation("new-product-survey", (byte) 0),
taskAllocation("comprehensive-case-training", (byte) 1))); taskAllocation("comprehensive-case-training", (byte) 1)));
List<TrainingTask> result = service.listForStudent("stu-1", true); List<TrainingTask> result = service.listForStudent("stu-1", true);
assertEquals(List.of("new-product-survey"), result.stream() assertEquals(java.util.Arrays.asList("new-product-survey"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }
@ -876,19 +876,19 @@ class TrainingTaskServiceImplTest {
TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTaskServiceImpl service = studentTaskService("class-1");
TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask legacy = storedTask("task-1", "new-product-survey");
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(legacy, comprehensive));
TrainingTaskClassConfig disabled = overrideTask("config-2", "class-1", "comprehensive-case-training"); TrainingTaskClassConfig disabled = overrideTask("config-2", "class-1", "comprehensive-case-training");
disabled.setEnabled(Boolean.FALSE); disabled.setEnabled(Boolean.FALSE);
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null))
.thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), disabled)); .thenReturn(java.util.Arrays.asList(overrideTask("config-1", "class-1", "new-product-survey"), disabled));
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( when(service.taskAllocationMapper.selectByExample(any())).thenReturn(java.util.Arrays.asList(
taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1),
taskAllocation("new-product-survey", (byte) 0), taskAllocation("new-product-survey", (byte) 0),
taskAllocation("comprehensive-case-training", (byte) 0))); taskAllocation("comprehensive-case-training", (byte) 0)));
List<TrainingTask> result = service.listForStudent("stu-1", false); List<TrainingTask> result = service.listForStudent("stu-1", false);
assertEquals(List.of("new-product-survey"), result.stream() assertEquals(java.util.Arrays.asList("new-product-survey"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }
@ -900,7 +900,7 @@ class TrainingTaskServiceImplTest {
service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class);
service.schoolClassMapper = mock(SchoolClassMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class);
TrainingTask comprehensive = comprehensiveTrainingTask(); TrainingTask comprehensive = comprehensiveTrainingTask();
when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(comprehensive)); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(java.util.Arrays.asList(comprehensive));
when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)).thenReturn(Collections.emptyList()); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)).thenReturn(Collections.emptyList());
SchoolClass schoolClass = teachingClass("class-1", "teacher-1"); SchoolClass schoolClass = teachingClass("class-1", "teacher-1");
schoolClass.setSchoolId("school-1"); schoolClass.setSchoolId("school-1");
@ -911,7 +911,7 @@ class TrainingTaskServiceImplTest {
List<TrainingTask> result = service.listForTeachingClass("class-1", true, teacher); List<TrainingTask> result = service.listForTeachingClass("class-1", true, teacher);
assertEquals(List.of("comprehensive-case-training"), result.stream() assertEquals(java.util.Arrays.asList("comprehensive-case-training"), result.stream()
.map(TrainingTask::getTaskKey) .map(TrainingTask::getTaskKey)
.collect(java.util.stream.Collectors.toList())); .collect(java.util.stream.Collectors.toList()));
} }

Loading…
Cancel
Save