diff --git a/infrastructure/main.tf b/infrastructure/main.tf index fd87685ce..5582f3f5c 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -41,7 +41,7 @@ module "pre_api" { api_mgmt_rg = "ss-${var.env}-network-rg" api_mgmt_name = "sds-api-mgmt-${var.env}" display_name = "Pre Recorded Evidence API" - revision = "103" + revision = "104" product_id = module.pre_product[0].product_id path = "pre-api" service_url = local.apim_service_url diff --git a/pre-api-stg.yaml b/pre-api-stg.yaml index e3ed3b942..fc171c829 100644 --- a/pre-api-stg.yaml +++ b/pre-api-stg.yaml @@ -3259,6 +3259,10 @@ paths: in: query name: includeDeleted type: boolean + - description: The case status to search by + in: query + name: caseOpen + type: boolean - description: Sort by in: query name: sort diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/CaseControllerFT.java b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/CaseControllerFT.java index feac28ce6..1504f8c5a 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/CaseControllerFT.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/CaseControllerFT.java @@ -76,7 +76,6 @@ void updateCaseClosedToOpenSuccess() throws JsonProcessingException { dto.setState(CaseState.OPEN); dto.setClosedAt(null); var putCase2 = putCase(dto); - putCase2.prettyPrint(); assertResponseCode(putCase2, 204); assertMatchesDto(dto); } diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/RecordingControllerFT.java b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/RecordingControllerFT.java index c9e5836e0..2b3ac1659 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/RecordingControllerFT.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/RecordingControllerFT.java @@ -4,8 +4,11 @@ import io.restassured.response.Response; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import uk.gov.hmcts.reform.preapi.controllers.params.TestingSupportRoles; import uk.gov.hmcts.reform.preapi.dto.BookingDTO; +import uk.gov.hmcts.reform.preapi.dto.CaseDTO; import uk.gov.hmcts.reform.preapi.dto.CreateCaptureSessionDTO; import uk.gov.hmcts.reform.preapi.dto.RecordingDTO; import uk.gov.hmcts.reform.preapi.enums.CaseState; @@ -14,13 +17,14 @@ import java.sql.Timestamp; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; public class RecordingControllerFT extends FunctionalTestBase { - @DisplayName("Scenario: Restore recording") @Test + @DisplayName("Scenario: Restore recording") void undeleteRecording() { var recordingDetails = createRecording(); assertRecordingExists(recordingDetails.recordingId(), true); @@ -38,8 +42,8 @@ void undeleteRecording() { assertRecordingExists(recordingDetails.recordingId(), true); } - @DisplayName("Scenario: Create and update a recording") @Test + @DisplayName("Scenario: Create and update a recording") void shouldCreateAndUpdateRecording() throws JsonProcessingException { var captureSession = createCaptureSession(); var putCaptureSession = putCaptureSession(captureSession); @@ -61,8 +65,8 @@ void shouldCreateAndUpdateRecording() throws JsonProcessingException { assertThat(response2.body().jsonPath().getString("filename")).isEqualTo("updated.file"); } - @DisplayName("Scenario: Create and update a recording in closed case") @Test + @DisplayName("Scenario: Create and update a recording in closed case") void upsertRecordingCaseClosed() throws JsonProcessingException { // create case, booking and capture session var captureSession = createCaptureSession(); @@ -104,8 +108,8 @@ void upsertRecordingCaseClosed() throws JsonProcessingException { + ") is associated with a case in the state CLOSED. Must be in state OPEN."); } - @DisplayName("Scenario: Create and update a recording in case pending closure") @Test + @DisplayName("Scenario: Create and update a recording in case pending closure") void upsertRecordingCasePendingClosure() throws JsonProcessingException { // create case, booking and capture session var captureSession = createCaptureSession(); @@ -147,8 +151,8 @@ void upsertRecordingCasePendingClosure() throws JsonProcessingException { + ") is associated with a case in the state PENDING_CLOSURE. Must be in state OPEN."); } - @DisplayName("Delete a recording") @Test + @DisplayName("Delete a recording") void shouldDeleteRecording() { var recording = createRecording(); assertRecordingExists(recording.recordingId(), true); @@ -159,8 +163,8 @@ void shouldDeleteRecording() { assertRecordingExists(recording.recordingId(), false); } - @DisplayName("Delete a recording that does not exist") @Test + @DisplayName("Delete a recording that does not exist") void deleteRecordingThatDoesntExist() { var id = UUID.randomUUID(); assertRecordingExists(id, false); @@ -169,8 +173,8 @@ void deleteRecordingThatDoesntExist() { assertResponseCode(deleteResponse, 404); } - @DisplayName("Undelete a recording should cascade to associated capture sessions, bookings and cases") @Test + @DisplayName("Undelete a recording should cascade to associated capture sessions, bookings and cases") void shouldUndeleteRecording() { // create recording var recordingDetails = createRecording(); @@ -205,8 +209,8 @@ void shouldUndeleteRecording() { assertCaseExists(recordingDetails.caseId(), true); } - @DisplayName("Should sort by created at desc when sort param not set and by sort param otherwise") @Test + @DisplayName("Should sort by created at desc when sort param not set and by sort param otherwise") void getRecordingsSortBy() throws JsonProcessingException { var details = createRecording(); assertRecordingExists(details.recordingId(), true); @@ -271,8 +275,8 @@ void getRecordingTotalVersionCount() throws JsonProcessingException { assertThat(getRecording3.getBody().as(RecordingDTO.class).getTotalVersionCount()).isEqualTo(2); } - @DisplayName("Should throw 400 error when sort param is invalid") @Test + @DisplayName("Should throw 400 error when sort param is invalid") void getRecordingsSortInvalidParam() { var getRecordings = doGetRequest( RECORDINGS_ENDPOINT + "?sort=invalidParam,asc", @@ -284,6 +288,71 @@ void getRecordingsSortInvalidParam() { .isEqualTo("Invalid sort parameter 'invalidParam' for 'uk.gov.hmcts.reform.preapi.entities.Recording'"); } + @ParameterizedTest + @DisplayName("Should search recordings by case open when recording's case is open") + @EnumSource(value = TestingSupportRoles.class, names = { "SUPER_USER", "LEVEL_1" }) + void getRecordingsByCaseOpenTrue(TestingSupportRoles testingSupportRole) { + var details = createRecording(); + assertRecordingExists(details.recordingId(), true); + + var getRecordingsCaseOpenTrue = doGetRequest( + RECORDINGS_ENDPOINT + "?caseOpen=true&captureSessionId=" + details.captureSessionId(), + testingSupportRole + ); + assertResponseCode(getRecordingsCaseOpenTrue, 200); + var recordingsCaseOpenTrue = getRecordingsCaseOpenTrue.jsonPath() + .getList("_embedded.recordingDTOList", RecordingDTO.class); + assertThat(recordingsCaseOpenTrue).hasSize(1); + assertThat(recordingsCaseOpenTrue.getFirst()).isNotNull(); + + var getRecordingsCaseOpenFalse = doGetRequest( + RECORDINGS_ENDPOINT + "?caseOpen=false&captureSessionId=" + details.captureSessionId(), + testingSupportRole + ); + var recordingsCaseOpenFalse = getRecordingsCaseOpenFalse.jsonPath() + .getList("_embedded.recordingDTOList", RecordingDTO.class); + assertThat(recordingsCaseOpenFalse).isEmpty(); + } + + @ParameterizedTest + @DisplayName("Should search recordings by case open when recording's case is closed") + @EnumSource(value = TestingSupportRoles.class, names = { "SUPER_USER", "LEVEL_1" }) + void getRecordingsByCaseOpenFalse(TestingSupportRoles testingSupportRole) throws JsonProcessingException { + var details = createRecording(); + var recording = assertRecordingExists(details.recordingId(), true) + .jsonPath().getObject("$", RecordingDTO.class); + + var getCase = doGetRequest(CASES_ENDPOINT + "/" + recording.getCaseId(), TestingSupportRoles.SUPER_USER); + assertResponseCode(getCase, 200); + + // mark case as closed + var caseDto = getCase.jsonPath().getObject("$", CaseDTO.class); + var createDto = convertDtoToCreateDto(caseDto); + createDto.setState(CaseState.CLOSED); + createDto.setClosedAt(Timestamp.from(Instant.now().minus(1, ChronoUnit.DAYS))); + var putCase = putCase(createDto); + assertResponseCode(putCase, 204); + assertCaseExists(caseDto.getId(), true); + + var getRecordingsCaseOpenTrue = doGetRequest( + RECORDINGS_ENDPOINT + "?caseOpen=true&captureSessionId=" + details.captureSessionId(), + testingSupportRole + ); + assertResponseCode(getRecordingsCaseOpenTrue, 200); + var recordingsCaseOpenTrue = getRecordingsCaseOpenTrue.jsonPath() + .getList("_embedded.recordingDTOList", RecordingDTO.class); + assertThat(recordingsCaseOpenTrue).isEmpty(); + + var getRecordingsCaseOpenFalse = doGetRequest( + RECORDINGS_ENDPOINT + "?caseOpen=false&captureSessionId=" + details.captureSessionId(), + testingSupportRole + ); + var recordingsCaseOpenFalse = getRecordingsCaseOpenFalse.jsonPath() + .getList("_embedded.recordingDTOList", RecordingDTO.class); + assertThat(recordingsCaseOpenFalse).hasSize(1); + assertThat(recordingsCaseOpenFalse.getFirst()).isNotNull(); + } + @Test @DisplayName("Should throw 403 when LEVEL 4 user attempts to search recordings") void getRecordingsLevel4() { diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/UserControllerFT.java b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/UserControllerFT.java index c40b6019f..19b193a97 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/UserControllerFT.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/UserControllerFT.java @@ -237,7 +237,6 @@ void userFilteredByAppActiveStatus() throws JsonProcessingException { TestingSupportRoles.SUPER_USER ); assertResponseCode(responseActiveTrueForDeletedCourtAccess, 200); - responseActiveTrueForDeletedCourtAccess.prettyPrint(); assertThat(responseActiveTrueForDeletedCourtAccess.body().jsonPath().getInt("page.totalElements")) .isEqualTo(0); } diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/RecordingServiceIT.java b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/RecordingServiceIT.java index cf5f5decc..0e0094615 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/RecordingServiceIT.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/RecordingServiceIT.java @@ -8,6 +8,7 @@ import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.context.SecurityContextHolder; import uk.gov.hmcts.reform.preapi.controllers.params.SearchRecordings; +import uk.gov.hmcts.reform.preapi.enums.CaseState; import uk.gov.hmcts.reform.preapi.enums.CourtType; import uk.gov.hmcts.reform.preapi.enums.RecordingOrigin; import uk.gov.hmcts.reform.preapi.security.authentication.UserAuthentication; @@ -34,8 +35,8 @@ private static void mockNonAdminUser(UUID courtId) { SecurityContextHolder.getContext().setAuthentication(mockAuth); } - @Transactional @Test + @Transactional void searchRecordingsAsAdmin() { mockAdminUser(); @@ -84,8 +85,8 @@ void searchRecordingsAsAdmin() { Assertions.assertTrue(recordings2.stream().anyMatch(recording -> recording.getId().equals(recording2.getId()))); } - @Transactional @Test + @Transactional void searchRecordingsAsNonAdmin() { var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234"); entityManager.persist(court); @@ -137,7 +138,7 @@ void searchRecordingsAsNonAdmin() { @Test @Transactional - void getNextVersionNumberSuccess() { + void searchRecordingsByCaseOpenAsNonAdmin() { var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234"); entityManager.persist(court); @@ -166,6 +167,106 @@ void getNextVersionNumberSuccess() { var recording1 = HelperFactory.createRecording(captureSession, null, 1, "filename", null); entityManager.persist(recording1); + var search = new SearchRecordings(); + search.setCaseOpen(true); + + var recordings = recordingService.findAll(search, false, Pageable.unpaged()).toList(); + Assertions.assertEquals(1, recordings.size()); + Assertions.assertEquals(recordings.getFirst().getId(), recording1.getId()); + + search.setCaseOpen(false); + var message = Assertions.assertThrows( + AccessDeniedException.class, + () -> recordingService.findAll(search, true, Pageable.unpaged()).toList() + ).getMessage(); + Assertions.assertEquals(message, "Access Denied"); + } + + @Test + @Transactional + void searchRecordingsByCaseOpenAsAdmin() { + var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234"); + entityManager.persist(court); + + mockAdminUser(); + + var caseEntity = HelperFactory.createCase(court, "CASE12345", true, null); + entityManager.persist(caseEntity); + + var booking = HelperFactory.createBooking(caseEntity, Timestamp.from(Instant.now()), null); + entityManager.persist(booking); + + var captureSession = HelperFactory.createCaptureSession( + booking, + RecordingOrigin.PRE, + null, + null, + null, + null, + null, + null, + null, + null + ); + entityManager.persist(captureSession); + + var recording1 = HelperFactory.createRecording(captureSession, null, 1, "filename", null); + entityManager.persist(recording1); + entityManager.flush(); + + var searchTrue = new SearchRecordings(); + searchTrue.setCaseOpen(true); + var searchFalse = new SearchRecordings(); + searchFalse.setCaseOpen(false); + + var recordings1 = recordingService.findAll(searchTrue, false, Pageable.unpaged()).toList(); + Assertions.assertEquals(1, recordings1.size()); + Assertions.assertEquals(recordings1.getFirst().getId(), recording1.getId()); + var recordings2 = recordingService.findAll(searchFalse, false, Pageable.unpaged()).toList(); + Assertions.assertTrue(recordings2.isEmpty()); + + // mark case as closed + caseEntity.setState(CaseState.CLOSED); + entityManager.persist(caseEntity); + entityManager.flush(); + + var recordings3 = recordingService.findAll(searchTrue, false, Pageable.unpaged()).toList(); + Assertions.assertTrue(recordings3.isEmpty()); + var recordings4 = recordingService.findAll(searchFalse, false, Pageable.unpaged()).toList(); + Assertions.assertEquals(1, recordings4.size()); + Assertions.assertEquals(recordings4.getFirst().getId(), recording1.getId()); + } + + @Test + @Transactional + void getNextVersionNumberSuccess() { + var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234"); + entityManager.persist(court); + + mockNonAdminUser(court.getId()); + + var caseEntity = HelperFactory.createCase(court, "CASE12345", true, null); + entityManager.persist(caseEntity); + + var booking = HelperFactory.createBooking(caseEntity, Timestamp.from(Instant.now()), null); + entityManager.persist(booking); + + var captureSession = HelperFactory.createCaptureSession( + booking, + RecordingOrigin.PRE, + null, + null, + null, + null, + null, + null, + null, + null + ); + entityManager.persist(captureSession); + + var recording1 = HelperFactory.createRecording(captureSession, null, 1, "filename", null); + entityManager.persist(recording1); var nextVersion1 = recordingService.getNextVersionNumber(recording1.getId()); assertThat(nextVersion1).isEqualTo(2); diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/RecordingController.java b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/RecordingController.java index 25e31035f..53bc2f60e 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/RecordingController.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/RecordingController.java @@ -113,6 +113,11 @@ public ResponseEntity getRecordingById( description = "Include recordings marked as deleted", schema = @Schema(implementation = Boolean.class) ) + @Parameter( + name = "caseOpen", + description = "The case status to search by", + schema = @Schema(implementation = Boolean.class) + ) @Parameter( name = "sort", description = "Sort by", @@ -150,7 +155,6 @@ public HttpEntity>> searchRecordings( } return ResponseEntity.ok(assembler.toModel(resultPage)); - } @PutMapping("/{recordingId}") diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/TestingSupportController.java b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/TestingSupportController.java index 14656a28a..92d86d8d6 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/TestingSupportController.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/TestingSupportController.java @@ -236,7 +236,7 @@ public ResponseEntity> shouldDeleteRecordingsForBooking() { var caseEntity = new Case(); caseEntity.setId(UUID.randomUUID()); - caseEntity.setReference(RandomStringUtils.randomAlphabetic(5)); + caseEntity.setReference(RandomStringUtils.randomAlphabetic(9)); caseEntity.setCourt(court); caseEntity.setOrigin(RecordingOrigin.PRE); caseRepository.save(caseEntity); diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/params/SearchRecordings.java b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/params/SearchRecordings.java index 1ef7d2458..bf93dd2cc 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/params/SearchRecordings.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/params/SearchRecordings.java @@ -29,6 +29,7 @@ public class SearchRecordings { private Timestamp startedAtUntil; private List authorisedBookings; private UUID authorisedCourt; + private Boolean caseOpen; public String getCaseReference() { return caseReference != null && !caseReference.isEmpty() ? caseReference : null; diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/repositories/RecordingRepository.java b/src/main/java/uk/gov/hmcts/reform/preapi/repositories/RecordingRepository.java index b1b2535a9..5e8279532 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/repositories/RecordingRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/repositories/RecordingRepository.java @@ -78,6 +78,12 @@ WHERE CONCAT(p.firstName, ' ', p.lastName) ILIKE %:#{#searchParams.defendantName AND p.deletedAt IS NULL ) ) + AND ( + :#{#searchParams.caseOpen} IS NULL + OR (:#{#searchParams.caseOpen} = TRUE + AND r.captureSession.booking.caseId.state IN ('OPEN', 'PENDING_CLOSURE')) + OR (:#{#searchParams.caseOpen} = FALSE + AND r.captureSession.booking.caseId.state = 'CLOSED')) """ ) Page searchAllBy( diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/security/AuthorisationService.java b/src/main/java/uk/gov/hmcts/reform/preapi/security/AuthorisationService.java index ebeb774ae..280450f98 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/security/AuthorisationService.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/security/AuthorisationService.java @@ -163,4 +163,11 @@ public boolean canUpdateCaseState(UserAuthentication authentication, CreateCaseD || authentication.isAdmin() || authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_LEVEL_2")); } + + public boolean canSearchByCaseClosed(UserAuthentication authentication, Boolean caseOpen) { + return caseOpen == null + || caseOpen + || authentication.isAdmin() + || authentication.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_LEVEL_2")); + } } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/services/RecordingService.java b/src/main/java/uk/gov/hmcts/reform/preapi/services/RecordingService.java index c191b2394..dd687b4ef 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/services/RecordingService.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/services/RecordingService.java @@ -65,7 +65,12 @@ public RecordingDTO findById(UUID recordingId) { } @Transactional - @PreAuthorize("!#includeDeleted or @authorisationService.canViewDeleted(authentication)") + @PreAuthorize( + """ + (!#includeDeleted or @authorisationService.canViewDeleted(authentication)) + and @authorisationService.canSearchByCaseClosed(authentication, #params.getCaseOpen()) + """ + ) public Page findAll( SearchRecordings params, boolean includeDeleted, diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/controller/RecordingControllerTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/controller/RecordingControllerTest.java index 5461ab13e..f25adef1d 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/controller/RecordingControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/controller/RecordingControllerTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; @@ -515,6 +516,66 @@ public void testGetCasesIncludeDeletedTrue() throws Exception { verify(recordingService, times(1)).findAll(any(), eq(true), any()); } + @Test + @DisplayName("Should search by case open status = true") + void getRecordingsCaseOpenTrue() throws Exception { + var mockRecordingDTO = new RecordingDTO(); + mockRecordingDTO.setId(UUID.randomUUID()); + when(recordingService.findAll(any(), anyBoolean(), any())) + .thenReturn(new PageImpl<>(List.of(mockRecordingDTO))); + + mockMvc.perform(get("/recordings?caseOpen=true") + .with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.recordingDTOList").isNotEmpty()) + .andExpect(jsonPath("$._embedded.recordingDTOList[0].id").value(mockRecordingDTO.getId().toString())); + + var argCaptor = ArgumentCaptor.forClass(SearchRecordings.class); + verify(recordingService, times(1)).findAll(argCaptor.capture(), eq(false), any()); + + assertThat(argCaptor.getValue().getCaseOpen()).isTrue(); + } + + @Test + @DisplayName("Should search by case open status = false") + void getRecordingsCaseOpenFalse() throws Exception { + var mockRecordingDTO = new RecordingDTO(); + mockRecordingDTO.setId(UUID.randomUUID()); + when(recordingService.findAll(any(), anyBoolean(), any())) + .thenReturn(new PageImpl<>(List.of(mockRecordingDTO))); + + mockMvc.perform(get("/recordings?caseOpen=false") + .with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.recordingDTOList").isNotEmpty()) + .andExpect(jsonPath("$._embedded.recordingDTOList[0].id").value(mockRecordingDTO.getId().toString())); + + var argCaptor = ArgumentCaptor.forClass(SearchRecordings.class); + verify(recordingService, times(1)).findAll(argCaptor.capture(), eq(false), any()); + + assertThat(argCaptor.getValue().getCaseOpen()).isFalse(); + } + + @Test + @DisplayName("Should search by case open status = null") + void getRecordingsCaseOpenNull() throws Exception { + var mockRecordingDTO = new RecordingDTO(); + mockRecordingDTO.setId(UUID.randomUUID()); + when(recordingService.findAll(any(), anyBoolean(), any())) + .thenReturn(new PageImpl<>(List.of(mockRecordingDTO))); + + mockMvc.perform(get("/recordings") + .with(csrf())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.recordingDTOList").isNotEmpty()) + .andExpect(jsonPath("$._embedded.recordingDTOList[0].id").value(mockRecordingDTO.getId().toString())); + + var argCaptor = ArgumentCaptor.forClass(SearchRecordings.class); + verify(recordingService, times(1)).findAll(argCaptor.capture(), eq(false), any()); + + assertThat(argCaptor.getValue().getCaseOpen()).isNull(); + } + @DisplayName("Should undelete a recording by id and return a 200 response") @Test void undeleteRecordingSuccess() throws Exception { diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/controller/ReportControllerTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/controller/ReportControllerTest.java index e75b6fef5..de2a1d7bd 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/controller/ReportControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/controller/ReportControllerTest.java @@ -29,7 +29,7 @@ import java.sql.Timestamp; import java.time.Duration; import java.time.Instant; -import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; @@ -458,7 +458,7 @@ void reportUserPrimaryCourtsSuccess() throws Exception { .andExpect(jsonPath("$[0].active").value(dto.getActive())) .andExpect(jsonPath("$[0].role_name").value(dto.getRoleName())) .andExpect(jsonPath("$[0].last_access").value(dto.getLastAccess().toInstant() - .atOffset(OffsetDateTime.now().getOffset()) + .atOffset(ZoneOffset.UTC) .format(DateTimeFormatter .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS+00:00")))); } diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/controller/params/SearchRecordingsTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/controller/params/SearchRecordingsTest.java index c91581f80..61eb0c9f5 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/controller/params/SearchRecordingsTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/controller/params/SearchRecordingsTest.java @@ -7,7 +7,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; public class SearchRecordingsTest { - @Test public void getCaseReference() { var searchRecordings = new SearchRecordings(); @@ -46,7 +45,8 @@ public void getDefendantName() { searchRecordings.setDefendantName(null); assertNull(searchRecordings.getDefendantName()); } - + + @Test public void getId() { var searchRecordings = new SearchRecordings(); searchRecordings.setId("abc"); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/security/AuthorisationServiceTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/security/AuthorisationServiceTest.java index 854968177..438e3cc40 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/security/AuthorisationServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/security/AuthorisationServiceTest.java @@ -802,6 +802,41 @@ void hasUpsertAccessUserIsNotAdminAndNoBookingAccess() { assertFalse(authorisationService.hasUpsertAccess(authenticationUser, dto)); } + @Test + @DisplayName("Should grant access when caseOpen param is null") + void canSearchByCaseClosedCaseOpenNull() { + assertTrue(authorisationService.canSearchByCaseClosed(authenticationUser, null)); + } + + @Test + @DisplayName("Should grant access when caseOpen param is true") + void canSearchByCaseClosedCaseOpenTrue() { + assertTrue(authorisationService.canSearchByCaseClosed(authenticationUser, true)); + } + + @Test + @DisplayName("Should grant access when caseOpen param is false and user is admin") + void canSearchByCaseClosedCaseOpenFalseIsAdmin() { + when(authenticationUser.isAdmin()).thenReturn(true); + assertTrue(authorisationService.canSearchByCaseClosed(authenticationUser, false)); + } + + @Test + @DisplayName("Should grant access when caseOpen param is false and user is level 2") + void canSearchByCaseClosedCaseOpenFalseIsLevel2() { + when(authenticationUser.isAdmin()).thenReturn(false); + when(authenticationUser.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_LEVEL_2"))); + assertTrue(authorisationService.canSearchByCaseClosed(authenticationUser, false)); + } + + @Test + @DisplayName("Should not grant access when caseOpen param is false and user is not admin or level 2") + void canSearchByCaseClosedCaseOpenFalseIsNotAdminOrLevel2() { + when(authenticationUser.isAdmin()).thenReturn(false); + when(authenticationUser.getAuthorities()).thenReturn(List.of(new SimpleGrantedAuthority("ROLE_LEVEL_3"))); + assertFalse(authorisationService.canSearchByCaseClosed(authenticationUser, false)); + } + @Test @DisplayName("Should grant upsert access when the user has access to recording for edit requests") void hasUpsertAccessEditRequest() {