Skip to content

S28 3734: Filter Recordings By Case Open/Closed #992

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion infrastructure/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions pre-api-stg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,8 +35,8 @@ private static void mockNonAdminUser(UUID courtId) {
SecurityContextHolder.getContext().setAuthentication(mockAuth);
}

@Transactional
@Test
@Transactional
void searchRecordingsAsAdmin() {
mockAdminUser();

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -137,7 +138,7 @@ void searchRecordingsAsNonAdmin() {

@Test
@Transactional
void getNextVersionNumberSuccess() {
void searchRecordingsByCaseOpenAsNonAdmin() {
var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234");
entityManager.persist(court);

Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public ResponseEntity<RecordingDTO> 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",
Expand Down Expand Up @@ -150,7 +155,6 @@ public HttpEntity<PagedModel<EntityModel<RecordingDTO>>> searchRecordings(
}

return ResponseEntity.ok(assembler.toModel(resultPage));

}

@PutMapping("/{recordingId}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public ResponseEntity<Map<String, String>> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class SearchRecordings {
private Timestamp startedAtUntil;
private List<UUID> authorisedBookings;
private UUID authorisedCourt;
private Boolean caseOpen;

public String getCaseReference() {
return caseReference != null && !caseReference.isEmpty() ? caseReference : null;
Expand Down
Loading