diff --git a/compose-local-deps.yml b/compose-local-deps.yml index 8e84f37a29..8065ed508a 100644 --- a/compose-local-deps.yml +++ b/compose-local-deps.yml @@ -87,6 +87,21 @@ services: ports: - "5432:5432" + it-postgres: + network_mode: bridge + container_name: it-postgres + image: postgres:16 + volumes: + - ./src/main/resources/db_scripts/postgres-rutherford-create-script.sql:/docker-entrypoint-initdb.d/00-isaac-create.sql:ro + - ./src/main/resources/db_scripts/postgres-rutherford-functions.sql:/docker-entrypoint-initdb.d/01-isaac-functions.sql:ro + - ./src/main/resources/db_scripts/quartz_scheduler_create_script.sql:/docker-entrypoint-initdb.d/02-isaac-quartz.sql:ro + - ./src/test/resources/test-postgres-rutherford-data-dump.sql:/docker-entrypoint-initdb.d/03-isaac-test-data.sql:ro + environment: + POSTGRES_USER: rutherford + POSTGRES_PASSWORD: rutherf0rd + ports: + - "5433:5432" + # app-physics: # network_mode: bridge # container_name: app-physics diff --git a/src/main/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacade.java b/src/main/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacade.java index 2fc9011302..e372a0a43e 100644 --- a/src/main/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacade.java +++ b/src/main/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacade.java @@ -197,9 +197,16 @@ public final Response getAvailableQuizzes(@Context final Request request, try { String userRoleString = Role.STUDENT.name(); // Allow anonymous users to list STUDENT quizzes. + boolean showNofilterQuizzes = false; + AbstractSegueUserDTO currentUser = userManager.getCurrentUser(httpServletRequest); if (currentUser instanceof RegisteredUserDTO) { userRoleString = ((RegisteredUserDTO) currentUser).getRole().name(); + try { + showNofilterQuizzes = isUserStaff(userManager, (RegisteredUserDTO) currentUser); + } catch (final NoUserLoggedInException e) { + // Not possible inside this if block! + } } // Cache the list of quizzes based on current content version, user's role, and startIndex: @@ -217,7 +224,7 @@ public final Response getAvailableQuizzes(@Context final Request request, // FIXME: ** HARD-CODED DANGER AHEAD ** // The limit parameter in the following call is hard-coded and should be returned to a more reasonable // number once we have a front-end pagination/load-more system in place. - ResultsWrapper summary = this.quizManager.getAvailableQuizzes(userRoleString, startIndex, 9000); + ResultsWrapper summary = this.quizManager.getAvailableQuizzes(userRoleString, startIndex, 9000, showNofilterQuizzes); return ok(summary).tag(etag) .cacheControl(getCacheControl(NEVER_CACHE_WITHOUT_ETAG_CHECK, false)) diff --git a/src/main/java/uk/ac/cam/cl/dtg/isaac/api/managers/QuizManager.java b/src/main/java/uk/ac/cam/cl/dtg/isaac/api/managers/QuizManager.java index 62e3e2ba4b..3c836bfd6a 100644 --- a/src/main/java/uk/ac/cam/cl/dtg/isaac/api/managers/QuizManager.java +++ b/src/main/java/uk/ac/cam/cl/dtg/isaac/api/managers/QuizManager.java @@ -84,12 +84,17 @@ public QuizManager(final AbstractConfigLoader properties, final ContentService c this.contentSummarizerService = contentSummarizerService; } - public ResultsWrapper getAvailableQuizzes(String visibleToRole, @Nullable Integer startIndex, @Nullable Integer limit) throws ContentManagerException { + public ResultsWrapper getAvailableQuizzes(String visibleToRole, @Nullable Integer startIndex, @Nullable Integer limit, boolean showNoFilterQuizzes) throws ContentManagerException { List fieldsToMatch = Lists.newArrayList(); fieldsToMatch.add(new GitContentManager.BooleanSearchClause( TYPE_FIELDNAME, Constants.BooleanOperator.AND, Collections.singletonList(QUIZ_TYPE))); + if (!showNoFilterQuizzes) { + fieldsToMatch.add(new GitContentManager.BooleanSearchClause(TAGS_FIELDNAME, BooleanOperator.NOT, + Collections.singletonList(HIDE_FROM_FILTER_TAG))); + } + if (null != visibleToRole) { fieldsToMatch.add(new GitContentManager.BooleanSearchClause(HIDDEN_FROM_ROLES_FIELDNAME, BooleanOperator.NOT, Collections.singletonList(visibleToRole))); diff --git a/src/test/java/uk/ac/cam/cl/dtg/isaac/IsaacTest.java b/src/test/java/uk/ac/cam/cl/dtg/isaac/IsaacTest.java index 75d596ed1e..6b9e01f64b 100644 --- a/src/test/java/uk/ac/cam/cl/dtg/isaac/IsaacTest.java +++ b/src/test/java/uk/ac/cam/cl/dtg/isaac/IsaacTest.java @@ -258,8 +258,8 @@ protected void initializeMocks() throws ContentManagerException, SegueDatabaseEx quizManager = createMock(QuizManager.class); registerDefaultsFor(quizManager, m -> { - expect(m.getAvailableQuizzes("STUDENT", 0, 9000)).andStubReturn(wrap(studentQuizSummary)); - expect(m.getAvailableQuizzes("TEACHER", 0, 9000)).andStubReturn(wrap(studentQuizSummary, teacherQuizSummary)); + expect(m.getAvailableQuizzes("STUDENT", 0, 9000, false)).andStubReturn(wrap(studentQuizSummary)); + expect(m.getAvailableQuizzes("TEACHER", 0, 9000, false)).andStubReturn(wrap(studentQuizSummary, teacherQuizSummary)); expect(m.findQuiz(studentQuiz.getId())).andStubReturn(studentQuiz); expect(m.findQuiz(studentQuizPreQuizAnswerChange.getId())).andStubReturn(studentQuizPreQuizAnswerChange); expect(m.findQuiz(studentQuizPostQuizAnswerChange.getId())).andStubReturn(studentQuizPostQuizAnswerChange); diff --git a/src/test/java/uk/ac/cam/cl/dtg/isaac/api/ITConstants.java b/src/test/java/uk/ac/cam/cl/dtg/isaac/api/ITConstants.java index dc6ec0cbb2..3bce434d84 100644 --- a/src/test/java/uk/ac/cam/cl/dtg/isaac/api/ITConstants.java +++ b/src/test/java/uk/ac/cam/cl/dtg/isaac/api/ITConstants.java @@ -129,4 +129,5 @@ public final class ITConstants { public static final String QUIZ_TEST_QUIZ_ID = "_quiz_test"; public static final String QUIZ_HIDDEN_FROM_ROLE_STUDENTS_QUIZ_ID = "_hidden_from_roles_student_quiz_test"; public static final String QUIZ_HIDDEN_FROM_ROLE_TUTORS_QUIZ_ID = "_hidden_from_roles_tutor_quiz_test"; + public static final String QUIZ_TEST_NOFILTER_QUIZ_ID = "_quiz_test_nofilter"; } diff --git a/src/test/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacadeIT.java b/src/test/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacadeIT.java index 56ad05feb9..76629a343c 100644 --- a/src/test/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacadeIT.java +++ b/src/test/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacadeIT.java @@ -19,7 +19,11 @@ import org.apache.commons.lang3.time.DateUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import uk.ac.cam.cl.dtg.isaac.dos.QuizFeedbackMode; +import uk.ac.cam.cl.dtg.isaac.dos.users.RegisteredUser; import uk.ac.cam.cl.dtg.isaac.dto.AssignmentStatusDTO; import uk.ac.cam.cl.dtg.isaac.dto.IsaacQuizDTO; import uk.ac.cam.cl.dtg.isaac.dto.QuizAssignmentDTO; @@ -32,6 +36,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.core.Request; import jakarta.ws.rs.core.Response; +import uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO; + import java.util.Date; import java.util.LinkedList; import java.util.List; @@ -164,6 +170,58 @@ public void getAvailableQuizzesEndpoint_getQuizzesAsTutor_returnsNoHiddenFromRol assertFalse(responseBody.getResults().stream().anyMatch(q -> q.getId().equals(QUIZ_HIDDEN_FROM_ROLE_TUTORS_QUIZ_ID))); } + @ParameterizedTest + @ValueSource(strings = { + ITConstants.TEST_TUTOR_EMAIL, + ITConstants.TEST_TEACHER_EMAIL, + }) + public void getAvailableQuizzesEndpoint_getQuizzesAsNonStaff_omitsNofilterTaggedQuizzes(String email) throws Exception { + // Arrange + // log in, create request + LoginResult login = loginAs(httpSession, email, "test1234"); + HttpServletRequest availableQuizzesRequest = createRequestWithCookies(new Cookie[]{login.cookie}); + replay(availableQuizzesRequest); + + // Act + // make request + Response getQuizzesResponse = quizFacade.getAvailableQuizzes(createNiceMock(Request.class), availableQuizzesRequest); + + // Assert + // check status code is OK + assertEquals(Response.Status.OK.getStatusCode(), getQuizzesResponse.getStatus()); + + // check nofilter quizzes are not returned as available + @SuppressWarnings("unchecked") ResultsWrapper responseBody = + (ResultsWrapper) getQuizzesResponse.getEntity(); + assertFalse(responseBody.getResults().stream().anyMatch(q -> q.getId().equals(QUIZ_TEST_NOFILTER_QUIZ_ID))); + } + + @ParameterizedTest + @ValueSource(strings = { + ITConstants.TEST_EVENTMANAGER_EMAIL, + ITConstants.TEST_EDITOR_EMAIL + }) + public void getAvailableQuizzesEndpoint_getQuizzesAsStaff_includesNofilterTaggedQuizzes(String email) throws Exception { + // Arrange + // log in, create request + LoginResult login = loginAs(httpSession, email, "test1234"); + HttpServletRequest availableQuizzesRequest = createRequestWithCookies(new Cookie[]{login.cookie}); + replay(availableQuizzesRequest); + + // Act + // make request + Response getQuizzesResponse = quizFacade.getAvailableQuizzes(createNiceMock(Request.class), availableQuizzesRequest); + + // Assert + // check status code is OK + assertEquals(Response.Status.OK.getStatusCode(), getQuizzesResponse.getStatus()); + + // check nofilter quizzes are returned as available + @SuppressWarnings("unchecked") ResultsWrapper responseBody = + (ResultsWrapper) getQuizzesResponse.getEntity(); + assertTrue(responseBody.getResults().stream().anyMatch(q -> q.getId().equals(QUIZ_TEST_NOFILTER_QUIZ_ID))); + } + @Test public void previewQuizEndpoint_previewInvisibleToStudentQuizAsTeacher_succeeds() throws Exception { // Arrange @@ -208,6 +266,34 @@ public void previewQuizEndpoint_previewHiddenFromRoleTutorQuizAsTutor_fails() th assertEquals("You do not have the permissions to complete this action", responseBody.getErrorMessage()); } + @ParameterizedTest + @ValueSource(strings = { + ITConstants.TEST_TUTOR_EMAIL, + ITConstants.TEST_TEACHER_EMAIL, + ITConstants.TEST_EVENTMANAGER_EMAIL, + ITConstants.TEST_EDITOR_EMAIL + }) + public void previewQuizEndpoint_previewNofilterQuizAsTutorOrAbove_succeeds(String email) throws Exception { + // Arrange + // log in as user, create request + LoginResult login = loginAs(httpSession, email, "test1234"); + HttpServletRequest previewQuizRequest = createRequestWithCookies(new Cookie[]{login.cookie}); + replay(previewQuizRequest); + + // Act + // make request + Response previewQuizResponse = quizFacade.previewQuiz(createNiceMock(Request.class), previewQuizRequest, + QUIZ_TEST_NOFILTER_QUIZ_ID); + + // Assert + // check status code is OK + assertEquals(Response.Status.OK.getStatusCode(), previewQuizResponse.getStatus()); + + // check the quiz is returned for preview + IsaacQuizDTO responseBody = (IsaacQuizDTO) previewQuizResponse.getEntity(); + assertEquals(QUIZ_TEST_NOFILTER_QUIZ_ID, responseBody.getId()); + } + @Test public void viewQuizRubricEndpoint_viewRubricAvailableToRoleStudent_succeeds() throws Exception { // Arrange diff --git a/src/test/resources/isaac-test-es-data.tar.gz b/src/test/resources/isaac-test-es-data.tar.gz index 0fcd5e3cdb..2a808bdcd3 100644 --- a/src/test/resources/isaac-test-es-data.tar.gz +++ b/src/test/resources/isaac-test-es-data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7260a3593f9a051113f8ee6cc4658fa13b8f6f7e60ae4d329688325673dcbe57 -size 2894090 +oid sha256:bd48a022d90d5862dd9a5be9e2cd4e8f6e493752d2602805b5306b255678928b +size 2922446