diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/catalog/provider/JavaCatalogProvider.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/catalog/provider/JavaCatalogProvider.java index f28c9955..9e239bdc 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/catalog/provider/JavaCatalogProvider.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/catalog/provider/JavaCatalogProvider.java @@ -397,7 +397,7 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv @SuppressWarnings({"unchecked", "rawtypes"}) private List parseOptions(String optionsJson) { - if (optionsJson == null || optionsJson.isEmpty()) return Collections.emptyList(); + if (optionsJson == null || optionsJson.isBlank()) return Collections.emptyList(); try { com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); List rawList = mapper.readValue(optionsJson, List.class); @@ -414,7 +414,7 @@ public class JavaCatalogProvider implements CatalogProvider, QuestionCatalogProv } return result; } catch (Exception e) { - return Collections.emptyList(); + throw exception(UNSAFE_PROVIDER_PAYLOAD); } } diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/practice/PracticeSessionServiceImpl.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/practice/PracticeSessionServiceImpl.java index 58123933..59adcb87 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/practice/PracticeSessionServiceImpl.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/practice/PracticeSessionServiceImpl.java @@ -579,8 +579,11 @@ public class PracticeSessionServiceImpl implements PracticeSessionService { || response.getDetails() == null || !Objects.equals(existing.getReportId(), response.getReportId()) || !Objects.equals(existing.getSessionId(), response.getSessionId())) { - log.warn("Invalid submit replay payload: id={}, storedReportId={}, storedSessionId={}, response={}", - existing.getId(), existing.getReportId(), existing.getSessionId(), existing.getResponseJson()); + log.warn("Invalid submit replay payload: id={}, storedReportId={}, storedSessionId={}, " + + "responseReportId={}, responseSessionId={}", + existing.getId(), existing.getReportId(), existing.getSessionId(), + response != null ? response.getReportId() : null, + response != null ? response.getSessionId() : null); throw exception(SUBMIT_IDEMPOTENCY_REPLAY_INVALID); } return response; diff --git a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafety.java b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafety.java index e9318377..2fe8ef10 100644 --- a/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafety.java +++ b/yudao-module-education/src/main/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafety.java @@ -33,8 +33,8 @@ public final class QuestionContentSafety { */ public static void validateVisibleProviderQuestion(CatalogQuestionDTO question, ErrorCode visibilityError) { if (question == null || question.getIsPublished() == null || !question.getIsPublished() - || "hidden".equalsIgnoreCase(question.getStatus()) - || "inactive".equalsIgnoreCase(question.getStatus())) { + || (question.getStatus() != null && !question.getStatus().isBlank() + && !"published".equalsIgnoreCase(question.getStatus()))) { throw exception(visibilityError); } } diff --git a/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionCatalogServiceImplTest.java b/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionCatalogServiceImplTest.java index 94ce2c16..b7ef3df2 100644 --- a/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionCatalogServiceImplTest.java +++ b/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionCatalogServiceImplTest.java @@ -298,12 +298,12 @@ class QuestionCatalogServiceImplTest { } @Test - void shouldAllowAllPublishedAndActiveItems() { - // Mixed types but all published and status != hidden/inactive → all pass + void shouldAllowPublishedItemsWithPublishedOrAbsentStatus() { + // Providers may omit status, but any explicit student-visible status must be PUBLISHED. CatalogQuestionDTO q1 = questionDto("q1", "Q1", "fill", "easy", true, null, null, null, null, null); CatalogQuestionDTO q2 = CatalogQuestionDTO.builder() .id("q2").stem("Q2").type("fill").difficulty("medium") - .isPublished(true).status("active").build(); + .isPublished(true).status("PUBLISHED").build(); CatalogQuestionDTO q3 = CatalogQuestionDTO.builder() .id("q3").stem("Q3").type("short_answer").difficulty("hard") .isPublished(true).status(null).build(); diff --git a/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafetyTest.java b/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafetyTest.java index 81e6d8e4..22b2e5b7 100644 --- a/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafetyTest.java +++ b/yudao-module-education/src/test/java/cn/iocoder/yudao/module/education/service/question/QuestionContentSafetyTest.java @@ -14,6 +14,20 @@ import static org.junit.jupiter.api.Assertions.*; class QuestionContentSafetyTest { + @Test + void shouldAllowOnlyPublishedProviderStatusWhenPresent() { + CatalogQuestionDTO published = CatalogQuestionDTO.builder().isPublished(true).status("PUBLISHED").build(); + assertDoesNotThrow(() -> QuestionContentSafety.validateVisibleProviderQuestion( + published, UNSAFE_PROVIDER_PAYLOAD)); + + for (String status : List.of("DRAFT", "DISABLED", "UNKNOWN", "HIDDEN", "INACTIVE")) { + CatalogQuestionDTO unsafe = CatalogQuestionDTO.builder().isPublished(true).status(status).build(); + ServiceException ex = assertThrows(ServiceException.class, + () -> QuestionContentSafety.validateVisibleProviderQuestion(unsafe, UNSAFE_PROVIDER_PAYLOAD)); + assertEquals(UNSAFE_PROVIDER_PAYLOAD.getCode(), ex.getCode()); + } + } + @Test void shouldAcceptAndOrderValidOptionBackedQuestion() { List options = QuestionContentSafety.validateProviderOptions(" choice ", List.of(