diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/EditControllerFT.java b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/EditControllerFT.java index e9035ddbd..00ab097ef 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/EditControllerFT.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/preapi/controllers/EditControllerFT.java @@ -1,14 +1,11 @@ package uk.gov.hmcts.reform.preapi.controllers; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import uk.gov.hmcts.reform.preapi.controllers.params.TestingSupportRoles; import uk.gov.hmcts.reform.preapi.dto.EditRequestDTO; import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; -import uk.gov.hmcts.reform.preapi.media.edit.EditInstructions; import uk.gov.hmcts.reform.preapi.util.FunctionalTestBase; import java.util.Map; @@ -24,7 +21,7 @@ public class EditControllerFT extends FunctionalTestBase { @Test @DisplayName("Should create an edit request from a csv") - void editFromCsvSuccess() throws JsonProcessingException { + void editFromCsvSuccess() { var recordingDetails = createRecording(); assertRecordingExists(recordingDetails.recordingId(), true); @@ -40,8 +37,7 @@ void editFromCsvSuccess() throws JsonProcessingException { assertThat(postResponse.getStatus()).isEqualTo(EditRequestStatus.PENDING); assertThat(postResponse.getEditInstruction()).isNotNull(); - var instructions = OBJECT_MAPPER.readValue(postResponse.getEditInstruction(), - new TypeReference() {}); + var instructions = postResponse.getEditInstruction(); assertThat(instructions).isNotNull(); var requestedInstructions = instructions.getRequestedInstructions(); diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/preapi/entities/EditRequestTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/entities/EditRequestTest.java index fc901b5c0..a0712cd7a 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/preapi/entities/EditRequestTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/entities/EditRequestTest.java @@ -51,7 +51,18 @@ public void testSaveAndRetrieveEditRequest() { var user = HelperFactory.createDefaultTestUser(); entityManager.persist(user); - var editRequest = HelperFactory.createEditRequest(recording, "{}", EditRequestStatus.PENDING, user, null, null); + var editRequest = HelperFactory.createEditRequest( + recording, + "{}", + EditRequestStatus.PENDING, + user, + null, + null, + null, + null, + null, + null + ); entityManager.persist(editRequest); entityManager.flush(); diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceIT.java b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceIT.java new file mode 100644 index 000000000..fb0adead7 --- /dev/null +++ b/src/integrationTest/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceIT.java @@ -0,0 +1,82 @@ +package uk.gov.hmcts.reform.preapi.services; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; +import uk.gov.hmcts.reform.preapi.enums.CourtType; +import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; +import uk.gov.hmcts.reform.preapi.enums.RecordingOrigin; +import uk.gov.hmcts.reform.preapi.util.HelperFactory; +import uk.gov.hmcts.reform.preapi.utils.IntegrationTestBase; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EditRequestServiceIT extends IntegrationTestBase { + @Autowired + private EditRequestService editRequestService; + + @Test + @Transactional + public void searchEditRequests() { + mockAdminUser(); + + var court = HelperFactory.createCourt(CourtType.CROWN, "Example Court", "1234"); + entityManager.persist(court); + + 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 recording = HelperFactory.createRecording(captureSession, null, 1, "filename", null); + entityManager.persist(recording); + + var user = HelperFactory.createDefaultTestUser(); + entityManager.persist(user); + + var editRequest = HelperFactory.createEditRequest( + recording, + "{}", + EditRequestStatus.PENDING, + user, + null, + null, + null, + null, + null, + null + ); + entityManager.persist(editRequest); + + var requests1 = editRequestService.findAll(recording.getId(), Pageable.unpaged()).toList(); + assertThat(requests1).hasSize(1); + assertThat(requests1.getFirst().getId()).isEqualTo(editRequest.getId()); + + var requests2 = editRequestService.findAll(UUID.randomUUID(), Pageable.unpaged()).toList(); + assertThat(requests2).isEmpty(); + + var requests3 = editRequestService.findAll(null, Pageable.unpaged()).toList(); + assertThat(requests3).hasSize(1); + assertThat(requests3.getFirst().getId()).isEqualTo(editRequest.getId()); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/EditController.java b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/EditController.java index d2b46ada4..2b48f9c38 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/controllers/EditController.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/controllers/EditController.java @@ -1,19 +1,33 @@ package uk.gov.hmcts.reform.preapi.controllers; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PagedResourcesAssembler; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.PagedModel; +import org.springframework.http.HttpEntity; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import uk.gov.hmcts.reform.preapi.controllers.base.PreApiController; +import uk.gov.hmcts.reform.preapi.dto.CreateEditRequestDTO; import uk.gov.hmcts.reform.preapi.dto.EditRequestDTO; import uk.gov.hmcts.reform.preapi.exception.BadRequestException; +import uk.gov.hmcts.reform.preapi.exception.PathPayloadMismatchException; +import uk.gov.hmcts.reform.preapi.exception.RequestedPageOutOfRangeException; import uk.gov.hmcts.reform.preapi.exception.UnsupportedMediaTypeException; import uk.gov.hmcts.reform.preapi.services.EditRequestService; @@ -22,7 +36,7 @@ @Slf4j @RestController @RequestMapping("/edits") -public class EditController { +public class EditController extends PreApiController { private final EditRequestService editRequestService; public static final String CSV_FILE_TYPE = "text/csv"; @@ -32,13 +46,56 @@ public EditController(EditRequestService editRequestService) { this.editRequestService = editRequestService; } - // todo add more roles when start working with UI @GetMapping("/{id}") - @PreAuthorize("hasAnyRole('ROLE_SUPER_USER')") + @PreAuthorize("hasAnyRole('ROLE_SUPER_USER', 'ROLE_LEVEL_3')") public ResponseEntity getEditRequestById(@PathVariable("id") UUID id) { return ResponseEntity.ok(editRequestService.findById(id)); } + @GetMapping + @Parameter( + name = "page", + description = "The page number of search result to return", + schema = @Schema(implementation = Integer.class), + example = "0" + ) + @Parameter( + name = "size", + description = "The number of search results to return per page", + schema = @Schema(implementation = Integer.class), + example = "10" + ) + @PreAuthorize("hasAnyRole('ROLE_SUPER_USER', 'ROLE_LEVEL_3')") + public HttpEntity>> searchRecordings( + @Parameter(schema = @Schema(implementation = UUID.class)) UUID sourceRecordingId, + @Parameter(hidden = true) Pageable pageable, + @Parameter(hidden = true) PagedResourcesAssembler assembler + ) { + var resultPage = editRequestService.findAll( + sourceRecordingId, + pageable + ); + + if (pageable.getPageNumber() > resultPage.getTotalPages()) { + throw new RequestedPageOutOfRangeException(pageable.getPageNumber(), resultPage.getTotalPages()); + } + + return ResponseEntity.ok(assembler.toModel(resultPage)); + } + + @PutMapping("/{id}") + @PreAuthorize("hasAnyRole('ROLE_SUPER_USER', 'ROLE_LEVEL_1', 'ROLE_LEVEL_3')") + public ResponseEntity upsertEditRequest( + @PathVariable("id") UUID id, + @Valid @RequestBody CreateEditRequestDTO createEditRequestDTO + ) { + if (!id.equals(createEditRequestDTO.getId())) { + throw new PathPayloadMismatchException("editRequestId", "createEditRequestDTO.id"); + } + + return getUpsertResponse(editRequestService.upsert(createEditRequestDTO), id); + } + @PreAuthorize("hasAnyRole('ROLE_SUPER_USER')") @PostMapping(value = "/from-csv/{sourceRecordingId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity createEditFromCsv(@PathVariable UUID sourceRecordingId, diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateEditRequestDTO.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateEditRequestDTO.java index f15471962..026f2a8fa 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateEditRequestDTO.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateEditRequestDTO.java @@ -4,21 +4,21 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; -import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Builder; +import jakarta.validation.constraints.Size; import lombok.Data; import lombok.NoArgsConstructor; +import uk.gov.hmcts.reform.preapi.dto.validators.CreateEditRequestStatusConstraint; import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; +import java.sql.Timestamp; import java.util.List; import java.util.UUID; @Data -@Builder @NoArgsConstructor -@AllArgsConstructor +@CreateEditRequestStatusConstraint @Schema(description = "CreateEditRequestDTO") @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class CreateEditRequestDTO { @@ -35,8 +35,21 @@ public class CreateEditRequestDTO { private EditRequestStatus status; @Valid - @Min(1) - @NotNull + @NotEmpty @Schema(description = "CreateEditRequestInstructions") private List editInstructions; + + @Schema(description = "CreateEditRequestJointlyAgreed") + private Boolean jointlyAgreed; + + @Size(max = 512) + @Schema(description = "CreateEditRequestRejectionReason") + private String rejectionReason; + + @Schema(description = "CreateEditRequestApprovedAt") + private Timestamp approvedAt; + + @Size(max = 100) + @Schema(description = "CreateEditRequestApprovedBy") + private String approvedBy; } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateRecordingDTO.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateRecordingDTO.java index 06f1a59fa..fa841a8dd 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateRecordingDTO.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/CreateRecordingDTO.java @@ -1,6 +1,5 @@ package uk.gov.hmcts.reform.preapi.dto; - import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditCutInstructionDTO.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditCutInstructionDTO.java index 3494dcdf9..5cc2578d1 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditCutInstructionDTO.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditCutInstructionDTO.java @@ -5,6 +5,7 @@ import com.opencsv.bean.CsvBindByName; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -25,17 +26,22 @@ public class EditCutInstructionDTO { @NotNull @CsvBindByName(column = "Start time of cut") @Schema(description = "EditInstructionStart") + @Pattern(regexp = "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$", message = "must be in format HH:MM:SS") private String startOfCut; @NotNull @CsvBindByName(column = "End time of cut") @Schema(description = "EditInstructionEnd") + @Pattern(regexp = "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$", message = "must be in format HH:MM:SS") private String endOfCut; @CsvBindByName(column = "Reason") private String reason; + @Schema(hidden = true) private Long start; + + @Schema(hidden = true) private Long end; public long getStart() { @@ -55,6 +61,9 @@ public long getEnd() { } private static long parseTime(String time) { + if (time == null) { + return -1; + } try { var units = time.split(":"); int hours = Integer.parseInt(units[0]); diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTO.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTO.java index 49b227fd6..ccfafa50c 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTO.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTO.java @@ -1,13 +1,17 @@ package uk.gov.hmcts.reform.preapi.dto; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import uk.gov.hmcts.reform.preapi.entities.EditRequest; import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; +import uk.gov.hmcts.reform.preapi.exception.UnknownServerException; +import uk.gov.hmcts.reform.preapi.media.edit.EditInstructions; import java.sql.Timestamp; import java.util.UUID; @@ -18,25 +22,87 @@ @AllArgsConstructor @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class EditRequestDTO { + @Schema(description = "EditRequestId") private UUID id; + + @Schema(description = "EditRequestSourceRecording") private RecordingDTO sourceRecording; - private String editInstruction; + + @Schema(description = "EditRequestEditInstruction") + private EditInstructions editInstruction; + + @Schema(description = "EditRequestStatus") private EditRequestStatus status; + + @Schema(description = "EditRequestStartedAt") private Timestamp startedAt; + + @Schema(description = "EditRequestFinishedAt") private Timestamp finishedAt; + + @Schema(description = "EditRequestCreatedById") private UUID createdById; + + @Schema(description = "EditRequestCreatedByName") + private String createdBy; + + @Schema(description = "EditRequestCreatedAt") private Timestamp createdAt; + + @Schema(description = "EditRequestModifiedAt") private Timestamp modifiedAt; + @Schema(description = "EditRequestJointlyAgreed") + private Boolean jointlyAgreed; + + @Schema(description = "EditRequestRejectionReason") + private String rejectionReason; + + @Schema(description = "EditRequestApprovedAt") + private Timestamp approvedAt; + + @Schema(description = "EditRequestApprovedBy") + private String approvedBy; + public EditRequestDTO(EditRequest editRequest) { this.id = editRequest.getId(); this.sourceRecording = new RecordingDTO(editRequest.getSourceRecording()); - this.editInstruction = editRequest.getEditInstruction(); + this.editInstruction = fromJson(editRequest.getEditInstruction()); + this.status = editRequest.getStatus(); + this.startedAt = editRequest.getStartedAt(); + this.finishedAt = editRequest.getFinishedAt(); + this.createdById = editRequest.getCreatedBy().getId(); + this.createdBy = editRequest.getCreatedBy().getFullName(); + this.createdAt = editRequest.getCreatedAt(); + this.modifiedAt = editRequest.getModifiedAt(); + this.jointlyAgreed = editRequest.getJointlyAgreed(); + this.rejectionReason = editRequest.getRejectionReason(); + this.approvedAt = editRequest.getApprovedAt(); + this.approvedBy = editRequest.getApprovedBy(); + } + + public EditRequestDTO(EditRequest editRequest, boolean includeSourceRecording) { + this.id = editRequest.getId(); + this.sourceRecording = includeSourceRecording ? new RecordingDTO(editRequest.getSourceRecording()) : null; + this.editInstruction = fromJson(editRequest.getEditInstruction()); this.status = editRequest.getStatus(); this.startedAt = editRequest.getStartedAt(); this.finishedAt = editRequest.getFinishedAt(); this.createdById = editRequest.getCreatedBy().getId(); this.createdAt = editRequest.getCreatedAt(); + this.createdBy = editRequest.getCreatedBy().getFullName(); this.modifiedAt = editRequest.getModifiedAt(); + this.jointlyAgreed = editRequest.getJointlyAgreed(); + this.rejectionReason = editRequest.getRejectionReason(); + this.approvedAt = editRequest.getApprovedAt(); + this.approvedBy = editRequest.getApprovedBy(); + } + + public static EditInstructions fromJson(String editInstructions) { + try { + return new ObjectMapper().readValue(editInstructions, EditInstructions.class); + } catch (Exception e) { + throw new UnknownServerException("Unable to read edit instructions"); + } } } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/RecordingDTO.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/RecordingDTO.java index 50f5b1fb3..083f0e0e1 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/dto/RecordingDTO.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/RecordingDTO.java @@ -1,6 +1,5 @@ package uk.gov.hmcts.reform.preapi.dto; - import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import io.swagger.v3.oas.annotations.media.Schema; @@ -8,8 +7,10 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import uk.gov.hmcts.reform.preapi.dto.base.BaseRecordingDTO; +import uk.gov.hmcts.reform.preapi.entities.EditRequest; import uk.gov.hmcts.reform.preapi.entities.Participant; import uk.gov.hmcts.reform.preapi.entities.Recording; +import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; import java.sql.Timestamp; import java.util.Comparator; @@ -49,6 +50,12 @@ public class RecordingDTO extends BaseRecordingDTO { @Schema(description = "RecordingTotalVersionCount") private int totalVersionCount; + @Schema(description = "RecordingEditRequests") + private List editRequests; + + @Schema(description = "RecordingEditStatus") + private EditRequestStatus editStatus; + public RecordingDTO(Recording recording) { id = recording.getId(); captureSession = new CaptureSessionDTO(recording.getCaptureSession()); @@ -77,5 +84,15 @@ public RecordingDTO(Recording recording) { .sorted(Comparator.comparing(Participant::getFirstName)) .map(ParticipantDTO::new)) .collect(Collectors.toList()); + editRequests = Stream.ofNullable(recording.getEditRequests()) + .flatMap(request -> + request + .stream() + .sorted(Comparator.comparing(EditRequest::getModifiedAt).reversed()) + .map(e -> new EditRequestDTO(e, false))) + .collect(Collectors.toList()); + editStatus = recording.getVersion() == 1 + ? (!editRequests.isEmpty() ? editRequests.getFirst().getStatus() : null) + : null; } } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusConstraint.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusConstraint.java new file mode 100644 index 000000000..08deb9184 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusConstraint.java @@ -0,0 +1,20 @@ +package uk.gov.hmcts.reform.preapi.dto.validators; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Constraint(validatedBy = CreateEditRequestStatusValidator.class) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface CreateEditRequestStatusConstraint { + String message() default "must have required data for status"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidator.java b/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidator.java new file mode 100644 index 000000000..a7a4bc965 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidator.java @@ -0,0 +1,56 @@ +package uk.gov.hmcts.reform.preapi.dto.validators; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import uk.gov.hmcts.reform.preapi.dto.CreateEditRequestDTO; +import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; + +public class CreateEditRequestStatusValidator + implements ConstraintValidator { + + @Override + public void initialize(CreateEditRequestStatusConstraint constraintAnnotation) { + } + + @Override + public boolean isValid(CreateEditRequestDTO dto, ConstraintValidatorContext cxt) { + if (dto.getStatus() == null) { + return true; + } + + if (dto.getStatus() == EditRequestStatus.REJECTED && dto.getRejectionReason() == null) { + cxt.disableDefaultConstraintViolation(); + cxt.buildConstraintViolationWithTemplate("must have rejection reason when status is REJECTED") + .addPropertyNode("rejectionReason") + .addConstraintViolation(); + return false; + } + + if (dto.getStatus() == EditRequestStatus.SUBMITTED && dto.getJointlyAgreed() == null) { + cxt.disableDefaultConstraintViolation(); + cxt.buildConstraintViolationWithTemplate("must have jointly agreed when status is SUBMITTED") + .addPropertyNode("jointlyAgreed") + .addConstraintViolation(); + return false; + } + + if (dto.getStatus() == EditRequestStatus.APPROVED) { + if (dto.getApprovedAt() == null) { + cxt.disableDefaultConstraintViolation(); + cxt.buildConstraintViolationWithTemplate("must have approved at when status is APPROVED") + .addPropertyNode("approvedAt") + .addConstraintViolation(); + return false; + } + if (dto.getApprovedBy() == null) { + cxt.disableDefaultConstraintViolation(); + cxt.buildConstraintViolationWithTemplate("must have approved by when status is APPROVED") + .addPropertyNode("approvedBy") + .addConstraintViolation(); + return false; + } + } + + return true; + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/entities/EditRequest.java b/src/main/java/uk/gov/hmcts/reform/preapi/entities/EditRequest.java index 547fbfeb5..7d403ff7e 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/entities/EditRequest.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/entities/EditRequest.java @@ -46,6 +46,18 @@ public class EditRequest extends CreatedModifiedAtEntity { @JoinColumn(name = "created_by", referencedColumnName = "id", nullable = false) private User createdBy; + @Column(name = "jointly_agreed") + private Boolean jointlyAgreed; + + @Column(name = "rejection_reason", length = 512) + private String rejectionReason; + + @Column(name = "approved_at") + private Timestamp approvedAt; + + @Column(name = "approved_by", length = 100) + private String approvedBy; + @Override public HashMap getDetailsForAudit() { var details = new HashMap(); @@ -56,6 +68,10 @@ public HashMap getDetailsForAudit() { details.put("startedAt", startedAt); details.put("finishedAt", finishedAt); details.put("createdBy", createdBy.getId()); + details.put("jointlyAgreed", jointlyAgreed); + details.put("rejectionReason", rejectionReason); + details.put("approvedAt", approvedAt); + details.put("approvedBy", approvedBy); return details; } } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/entities/Recording.java b/src/main/java/uk/gov/hmcts/reform/preapi/entities/Recording.java index ef11dd26b..8efa4c26b 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/entities/Recording.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/entities/Recording.java @@ -63,6 +63,9 @@ public class Recording extends BaseEntity implements ISoftDeletable { @JdbcTypeCode(SqlTypes.JSON) private String editInstruction; + @OneToMany(mappedBy = "sourceRecording") + private Set editRequests; + @Column(name = "deleted_at") private Timestamp deletedAt; diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/enums/EditRequestStatus.java b/src/main/java/uk/gov/hmcts/reform/preapi/enums/EditRequestStatus.java index c0569f170..4ca64c82c 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/enums/EditRequestStatus.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/enums/EditRequestStatus.java @@ -1,6 +1,10 @@ package uk.gov.hmcts.reform.preapi.enums; public enum EditRequestStatus { + DRAFT, + SUBMITTED, + APPROVED, + REJECTED, PENDING, PROCESSING, COMPLETE, diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/media/edit/EditInstructions.java b/src/main/java/uk/gov/hmcts/reform/preapi/media/edit/EditInstructions.java index 70280fb71..061c97702 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/media/edit/EditInstructions.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/media/edit/EditInstructions.java @@ -10,6 +10,6 @@ @Getter @AllArgsConstructor public class EditInstructions { - private final List requestedInstructions; - private final List ffmpegInstructions; + protected final List requestedInstructions; + protected final List ffmpegInstructions; } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/repositories/EditRequestRepository.java b/src/main/java/uk/gov/hmcts/reform/preapi/repositories/EditRequestRepository.java index 511d8f573..98ff35b6c 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/repositories/EditRequestRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/repositories/EditRequestRepository.java @@ -3,10 +3,13 @@ import jakarta.persistence.LockModeType; import jakarta.persistence.QueryHint; import org.jetbrains.annotations.NotNull; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Lock; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.QueryHints; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import uk.gov.hmcts.reform.preapi.entities.EditRequest; import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; @@ -24,6 +27,18 @@ public interface EditRequestRepository extends JpaRepository Optional findFirstByStatusIsOrderByCreatedAt(EditRequestStatus status); + @Query( + """ + SELECT e FROM EditRequest e + WHERE ( + CAST(:sourceRecordingId as uuid) IS NULL OR + e.sourceRecording.id = :sourceRecordingId + ) + ORDER BY e.modifiedAt DESC + """ + ) + Page searchAllBy(@Param("sourceRecordingId") UUID sourceRecordingId, Pageable pageable); + @Query("select e from EditRequest e where e.id = ?1") Optional findByIdNotLocked(@NotNull UUID id); } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/services/EditRequestService.java b/src/main/java/uk/gov/hmcts/reform/preapi/services/EditRequestService.java index f197abadb..36391c9eb 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/services/EditRequestService.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/services/EditRequestService.java @@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; @@ -91,6 +93,14 @@ public EditRequestDTO findById(UUID id) { .orElseThrow(() -> new NotFoundException("Edit Request: " + id)); } + @Transactional + @PreAuthorize("@authorisationService.hasRecordingAccess(authentication, #sourceRecordingId)") + public Page findAll(UUID sourceRecordingId, Pageable pageable) { + return editRequestRepository + .searchAllBy(sourceRecordingId, pageable) + .map(EditRequestDTO::new); + } + @Transactional public Optional getNextPendingEditRequest() { return editRequestRepository.findFirstByStatusIsOrderByCreatedAt(EditRequestStatus.PENDING); @@ -164,7 +174,10 @@ public void sendNotifications(Booking booking) { var createDto = new CreateRecordingDTO(); createDto.setId(newRecordingId); createDto.setParentRecordingId(request.getSourceRecording().getId()); - createDto.setEditInstructions(request.getEditInstruction()); + + var dump = new EditInstructionDump(request.getId(), fromJson(request.getEditInstruction())); + createDto.setEditInstructions(toJson(dump)); + createDto.setVersion(recordingService.getNextVersionNumber(request.getSourceRecording().getId())); createDto.setCaptureSessionId(request.getSourceRecording().getCaptureSession().getId()); createDto.setFilename(filename); @@ -223,14 +236,18 @@ public UpsertResult upsert(CreateEditRequestDTO dto) { request.setId(dto.getId()); request.setSourceRecording(sourceRecording); request.setStatus(dto.getStatus()); + request.setJointlyAgreed(dto.getJointlyAgreed()); + request.setApprovedAt(dto.getApprovedAt()); + request.setApprovedBy(dto.getApprovedBy()); + request.setRejectionReason(dto.getRejectionReason()); var editInstructions = invertInstructions(dto.getEditInstructions(), sourceRecording); request.setEditInstruction(toJson(new EditInstructions(dto.getEditInstructions(), editInstructions))); var isUpdate = req.isPresent(); if (!isUpdate) { - var user = ((UserAuthentication) SecurityContextHolder.getContext().getAuthentication()) - .getAppAccess().getUser(); + var auth = ((UserAuthentication) SecurityContextHolder.getContext().getAuthentication()); + var user = auth.isAppUser() ? auth.getAppAccess().getUser() : auth.getPortalAccess().getUser(); request.setCreatedBy(user); } @@ -244,12 +261,13 @@ public UpsertResult upsert(CreateEditRequestDTO dto) { public EditRequestDTO upsert(UUID sourceRecordingId, MultipartFile file) { // temporary code for create edit request with csv endpoint var id = UUID.randomUUID(); - upsert(CreateEditRequestDTO.builder() - .id(id) - .sourceRecordingId(sourceRecordingId) - .editInstructions(parseCsv(file)) - .status(EditRequestStatus.PENDING) - .build()); + var dto = new CreateEditRequestDTO(); + dto.setId(id); + dto.setSourceRecordingId(sourceRecordingId); + dto.setEditInstructions(parseCsv(file)); + dto.setStatus(EditRequestStatus.PENDING); + + upsert(dto); return editRequestRepository.findById(id) .map(EditRequestDTO::new) @@ -327,11 +345,23 @@ public List invertInstructions(List String toJson(E instructions) { try { return new ObjectMapper().writeValueAsString(instructions); } catch (JsonProcessingException e) { throw new UnknownServerException("Something went wrong: " + e.getMessage()); } } + + private EditInstructions fromJson(String editInstructions) { + try { + return new ObjectMapper().readValue(editInstructions, EditInstructions.class); + } catch (Exception e) { + log.error("Error reading edit instructions: {} with message: {}", editInstructions, e.getMessage()); + throw new UnknownServerException("Unable to read edit instructions"); + } + } + + private record EditInstructionDump(UUID editRequestId, EditInstructions editInstructions) { + } } diff --git a/src/main/java/uk/gov/hmcts/reform/preapi/tasks/RobotUserTask.java b/src/main/java/uk/gov/hmcts/reform/preapi/tasks/RobotUserTask.java index 610ad1635..2ff385ede 100644 --- a/src/main/java/uk/gov/hmcts/reform/preapi/tasks/RobotUserTask.java +++ b/src/main/java/uk/gov/hmcts/reform/preapi/tasks/RobotUserTask.java @@ -24,7 +24,10 @@ protected void signInRobotUser() { log.info("Sign in as robot user"); var user = userService.findByEmail(cronUserEmail); - var appAccess = user.getAppAccess().stream().findFirst() + var appAccess = user.getAppAccess() + .stream() + .filter(access -> access.getRole().getName().equals("Super User")) + .findFirst() .orElseThrow(() -> new RuntimeException( "Failed to authenticate as cron user with email " + cronUserEmail) ); diff --git a/src/main/resources/db/migration/V027__EditRequestNewColumns.sql b/src/main/resources/db/migration/V027__EditRequestNewColumns.sql new file mode 100644 index 000000000..81eb54ceb --- /dev/null +++ b/src/main/resources/db/migration/V027__EditRequestNewColumns.sql @@ -0,0 +1,4 @@ +ALTER TABLE public.edit_requests ADD COLUMN jointly_agreed BOOLEAN; +ALTER TABLE public.edit_requests ADD COLUMN rejection_reason VARCHAR(512); +ALTER TABLE public.edit_requests ADD COLUMN approved_at TIMESTAMPTZ; +ALTER TABLE public.edit_requests ADD COLUMN approved_by VARCHAR(100); diff --git a/src/main/resources/db/migration/V028__NewEditRequestStatuses.sql b/src/main/resources/db/migration/V028__NewEditRequestStatuses.sql new file mode 100644 index 000000000..55519636d --- /dev/null +++ b/src/main/resources/db/migration/V028__NewEditRequestStatuses.sql @@ -0,0 +1,4 @@ +ALTER TYPE public.EDIT_REQUEST_STATUS ADD VALUE 'DRAFT'; +ALTER TYPE public.EDIT_REQUEST_STATUS ADD VALUE 'SUBMITTED'; +ALTER TYPE public.EDIT_REQUEST_STATUS ADD VALUE 'APPROVED'; +ALTER TYPE public.EDIT_REQUEST_STATUS ADD VALUE 'REJECTED'; diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/controller/AuditControllerTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/controller/AuditControllerTest.java index cce112fe3..4060f2492 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/controller/AuditControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/controller/AuditControllerTest.java @@ -68,8 +68,6 @@ void createAuditEndpointCreated() throws Exception { var xUserId = UUID.randomUUID(); when(auditService.upsert(audit, xUserId)).thenReturn(UpsertResult.CREATED); - System.out.println(OBJECT_MAPPER.writeValueAsString(audit)); - MvcResult response = mockMvc.perform(put(getPath(audit.getId())) .with(csrf()) .header(X_USER_ID_HEADER, xUserId) @@ -94,8 +92,6 @@ void createAuditEndpointWithoutXUserIdCreated() throws Exception { var xUserId = UUID.randomUUID(); when(auditService.upsert(audit, xUserId)).thenReturn(UpsertResult.CREATED); - System.out.println(OBJECT_MAPPER.writeValueAsString(audit)); - MvcResult response = mockMvc.perform(put(getPath(audit.getId())) .with(csrf()) .content(OBJECT_MAPPER.writeValueAsString(audit)) diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/controller/EditControllerTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/controller/EditControllerTest.java index 3aeebe778..cc5f57619 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/controller/EditControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/controller/EditControllerTest.java @@ -8,21 +8,31 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageImpl; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.multipart.MultipartFile; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.PropertyNamingStrategy; import uk.gov.hmcts.reform.preapi.controllers.EditController; +import uk.gov.hmcts.reform.preapi.dto.CreateEditRequestDTO; +import uk.gov.hmcts.reform.preapi.dto.EditCutInstructionDTO; import uk.gov.hmcts.reform.preapi.dto.EditRequestDTO; +import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; +import uk.gov.hmcts.reform.preapi.enums.UpsertResult; import uk.gov.hmcts.reform.preapi.exception.NotFoundException; import uk.gov.hmcts.reform.preapi.security.service.UserAuthenticationService; import uk.gov.hmcts.reform.preapi.services.EditRequestService; import uk.gov.hmcts.reform.preapi.services.ScheduledTaskRunner; +import java.sql.Timestamp; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.util.List; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; @@ -31,8 +41,11 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static uk.gov.hmcts.reform.preapi.controllers.EditController.CSV_FILE_TYPE; @@ -41,7 +54,7 @@ @AutoConfigureMockMvc(addFilters = false) public class EditControllerTest { @Autowired - private MockMvc mockMvc; + private transient MockMvc mockMvc; @MockBean private EditRequestService editRequestService; @@ -65,6 +78,7 @@ void beforeEach() { @BeforeAll static void beforeAll() { OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'")); + OBJECT_MAPPER.setPropertyNamingStrategy(new PropertyNamingStrategy.SnakeCaseStrategy()); } @Test @@ -170,4 +184,276 @@ void getByIdNotFound() throws Exception { .andExpect(status().isNotFound()) .andExpect(jsonPath("$.message").value("Not found: Edit Request: " + id)); } + + @Test + @DisplayName("Should return 200 when searching by source recording id") + void searchRecordingsNoSourceId() throws Exception { + var id = UUID.randomUUID(); + var editRequest = new EditRequestDTO(); + editRequest.setId(UUID.randomUUID()); + + when(editRequestService.findAll(eq(id), any())).thenReturn(new PageImpl<>(List.of(editRequest))); + + mockMvc.perform(get(TEST_URL + "/edits") + .param("sourceRecordingId", id.toString()) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.editRequestDTOList[0].id").value(editRequest.getId().toString())); + } + + @Test + @DisplayName("Should return 201 when successfully created edit request") + void upsertEditRequestCreated() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.DRAFT); + + when(editRequestService.upsert(any(CreateEditRequestDTO.class))).thenReturn(UpsertResult.CREATED); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()) + .andExpect(header().string("Location", TEST_URL + "/edits/" + dto.getId())); + + verify(editRequestService, times(1)).upsert(any(CreateEditRequestDTO.class)); + } + + @Test + @DisplayName("Should return 204 when successfully updated edit request") + void upsertEditRequestUpdated() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.DRAFT); + + when(editRequestService.upsert(any(CreateEditRequestDTO.class))).thenReturn(UpsertResult.UPDATED); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isNoContent()) + .andExpect(header().string("Location", TEST_URL + "/edits/" + dto.getId())); + + verify(editRequestService, times(1)).upsert(any(CreateEditRequestDTO.class)); + } + + @Test + @DisplayName("Should return 400 when path and payload IDs do not match") + void upsertEditRequestPathPayloadMismatch() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.DRAFT); + var differentId = UUID.randomUUID(); + + mockMvc.perform(put(TEST_URL + "/edits/" + differentId) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message") + .value("Path editRequestId does not match payload property createEditRequestDTO.id")); + } + + @Test + @DisplayName("Should return 400 when startOfCut is null") + void validateStartOfCutIsNull() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.DRAFT); + + var result = mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andReturn(); + + assertThat(result.getResponse().getContentAsString()) + .isEqualTo("{\"editInstructions[0].startOfCut\":\"must not be null\"}"); + } + + @Test + @DisplayName("Should return 400 when sourceRecordingId is null") + void validateSourceRecordingIdIsNull() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.DRAFT); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.sourceRecordingId").value("must not be null")); + } + + @Test + @DisplayName("Should return 400 when editInstructions is null") + void validateEditInstructionsIsNull() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setStatus(EditRequestStatus.DRAFT); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()); + } + + @Test + @DisplayName("Should return 400 when editInstructions is empty") + void validateEditInstructionsIsEmpty() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of()); + dto.setStatus(EditRequestStatus.DRAFT); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.editInstructions").value("must not be empty")); + } + + @Test + @DisplayName("Should return 400 when status is null") + void validateStatusIsNull() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value("must not be null")); + } + + @Test + @DisplayName("Should return 400 when status is REJECTED and rejectionReason is null") + void validateRejectedStatusWithoutRejectionReason() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.REJECTED); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.rejectionReason").value("must have rejection reason when status is REJECTED")); + } + + @Test + @DisplayName("Should return 400 when status is SUBMITTED and jointlyAgreed is null") + void validateSubmittedStatusWithoutJointlyAgreed() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.SUBMITTED); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.jointlyAgreed").value("must have jointly agreed when status is SUBMITTED")); + } + + @Test + @DisplayName("Should return 400 when status is APPROVED and approvedAt is null") + void validateApprovedStatusWithoutApprovedAt() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.APPROVED); + dto.setApprovedBy("Someone"); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.approvedAt").value("must have approved at when status is APPROVED")); + } + + @Test + @DisplayName("Should return 400 when status is APPROVED and approvedBy is null") + void validateApprovedStatusWithoutApprovedBy() throws Exception { + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setEditInstructions(List.of(EditCutInstructionDTO.builder() + .startOfCut("00:00:00") + .endOfCut("00:00:01") + .build())); + dto.setStatus(EditRequestStatus.APPROVED); + dto.setApprovedAt(Timestamp.from(Instant.now())); + + mockMvc.perform(put(TEST_URL + "/edits/" + dto.getId()) + .with(csrf()) + .content(OBJECT_MAPPER.writeValueAsString(dto)) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.approvedBy").value("must have approved by when status is APPROVED")); + } } diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTOTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTOTest.java index 782d663fe..df04fb18d 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTOTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/dto/EditRequestDTOTest.java @@ -23,7 +23,7 @@ public class EditRequestDTOTest { static void setUp() { editRequest = new EditRequest(); editRequest.setId(UUID.randomUUID()); - editRequest.setEditInstruction("{}"); + editRequest.setEditInstruction("{\"requestedInstructions\": [], \"ffmpegInstructions\": []}"); editRequest.setStatus(EditRequestStatus.COMPLETE); editRequest.setStartedAt(Timestamp.from(Instant.now())); editRequest.setFinishedAt(Timestamp.from(Instant.now())); @@ -59,7 +59,46 @@ void testConstructor() { var dto = new EditRequestDTO(editRequest); assertThat(dto.getId()).isEqualTo(editRequest.getId()); - assertThat(dto.getEditInstruction()).isEqualTo(editRequest.getEditInstruction()); + assertThat(dto.getEditInstruction().getRequestedInstructions()).isEmpty(); + assertThat(dto.getEditInstruction().getFfmpegInstructions()).isEmpty(); + assertThat(dto.getStatus()).isEqualTo(editRequest.getStatus()); + assertThat(dto.getStartedAt()).isEqualTo(editRequest.getStartedAt()); + assertThat(dto.getFinishedAt()).isEqualTo(editRequest.getFinishedAt()); + assertThat(dto.getCreatedAt()).isEqualTo(editRequest.getCreatedAt()); + assertThat(dto.getModifiedAt()).isEqualTo(editRequest.getModifiedAt()); + assertThat(dto.getCreatedById()).isEqualTo(editRequest.getCreatedBy().getId()); + assertThat(dto.getSourceRecording().getId()).isEqualTo(editRequest.getSourceRecording().getId()); + } + + @Test + @DisplayName("Should create an edit request dto from edit request entity without source recording") + void testConstructorWithoutSourceRecording() { + var dto = new EditRequestDTO(editRequest, false); + + assertThat(dto.getId()).isEqualTo(editRequest.getId()); + assertThat(dto.getSourceRecording()).isNull(); + assertThat(dto.getEditInstruction().getRequestedInstructions()).isEmpty(); + assertThat(dto.getEditInstruction().getFfmpegInstructions()).isEmpty(); + assertThat(dto.getStatus()).isEqualTo(editRequest.getStatus()); + assertThat(dto.getStartedAt()).isEqualTo(editRequest.getStartedAt()); + assertThat(dto.getFinishedAt()).isEqualTo(editRequest.getFinishedAt()); + assertThat(dto.getCreatedById()).isEqualTo(editRequest.getCreatedBy().getId()); + assertThat(dto.getCreatedAt()).isEqualTo(editRequest.getCreatedAt()); + assertThat(dto.getModifiedAt()).isEqualTo(editRequest.getModifiedAt()); + assertThat(dto.getJointlyAgreed()).isEqualTo(editRequest.getJointlyAgreed()); + assertThat(dto.getRejectionReason()).isEqualTo(editRequest.getRejectionReason()); + assertThat(dto.getApprovedAt()).isEqualTo(editRequest.getApprovedAt()); + assertThat(dto.getApprovedBy()).isEqualTo(editRequest.getApprovedBy()); + } + + @Test + @DisplayName("Should create an edit request dto from edit request entity with source recording") + void testConstructorWithSourceRecording() { + var dto = new EditRequestDTO(editRequest, true); + + assertThat(dto.getId()).isEqualTo(editRequest.getId()); + assertThat(dto.getEditInstruction().getRequestedInstructions()).isEmpty(); + assertThat(dto.getEditInstruction().getFfmpegInstructions()).isEmpty(); assertThat(dto.getStatus()).isEqualTo(editRequest.getStatus()); assertThat(dto.getStartedAt()).isEqualTo(editRequest.getStartedAt()); assertThat(dto.getFinishedAt()).isEqualTo(editRequest.getFinishedAt()); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidatorTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidatorTest.java new file mode 100644 index 000000000..39d2402be --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/preapi/dto/validators/CreateEditRequestStatusValidatorTest.java @@ -0,0 +1,148 @@ +package uk.gov.hmcts.reform.preapi.dto.validators; + +import jakarta.validation.ConstraintValidatorContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uk.gov.hmcts.reform.preapi.dto.CreateEditRequestDTO; +import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; + +import java.sql.Timestamp; +import java.time.Instant; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class CreateEditRequestStatusValidatorTest { + + private CreateEditRequestStatusValidator validator; + + @BeforeEach + public void setUp() { + validator = new CreateEditRequestStatusValidator(); + } + + @Test + public void isValidStatusNullTrue() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(null); + var context = mock(ConstraintValidatorContext.class); + + assertTrue(validator.isValid(dto, context)); + } + + @Test + public void isValidRejectedRejectionReasonNullFalse() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.REJECTED); + dto.setRejectionReason(null); + var context = mock(ConstraintValidatorContext.class); + var builder = mock(ConstraintValidatorContext.ConstraintViolationBuilder.class); + var nodeBuilder = + mock(ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext.class); + + when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(builder); + when(builder.addPropertyNode(anyString())).thenReturn(nodeBuilder); + + assertFalse(validator.isValid(dto, context)); + + verify(context).disableDefaultConstraintViolation(); + verify(builder).addPropertyNode("rejectionReason"); + verify(nodeBuilder).addConstraintViolation(); + } + + @Test + public void isValidRejectedRejectionReasonNotNullTrue() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.REJECTED); + dto.setRejectionReason("Reason"); + var context = mock(ConstraintValidatorContext.class); + + assertTrue(validator.isValid(dto, context)); + } + + @Test + public void isValidSubmittedJointlyAgreedNullFalse() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.SUBMITTED); + dto.setJointlyAgreed(null); + var context = mock(ConstraintValidatorContext.class); + var builder = mock(ConstraintValidatorContext.ConstraintViolationBuilder.class); + var nodeBuilder = + mock(ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext.class); + + when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(builder); + when(builder.addPropertyNode(anyString())).thenReturn(nodeBuilder); + + assertFalse(validator.isValid(dto, context)); + + verify(context).disableDefaultConstraintViolation(); + verify(builder).addPropertyNode("jointlyAgreed"); + verify(nodeBuilder).addConstraintViolation(); + } + + @Test + public void isValidSubmittedJointlyAgreedNotNullTrue() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.SUBMITTED); + dto.setJointlyAgreed(true); + var context = mock(ConstraintValidatorContext.class); + + assertTrue(validator.isValid(dto, context)); + } + + @Test + public void isValidApprovedApprovedAtNullFalse() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.APPROVED); + dto.setApprovedAt(null); + var context = mock(ConstraintValidatorContext.class); + var builder = mock(ConstraintValidatorContext.ConstraintViolationBuilder.class); + var nodeBuilder = + mock(ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext.class); + + when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(builder); + when(builder.addPropertyNode(anyString())).thenReturn(nodeBuilder); + + assertFalse(validator.isValid(dto, context)); + + verify(context).disableDefaultConstraintViolation(); + verify(builder).addPropertyNode("approvedAt"); + verify(nodeBuilder).addConstraintViolation(); + } + + @Test + public void isValidApprovedApprovedByNullFalse() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.APPROVED); + dto.setApprovedAt(Timestamp.from(Instant.now())); + dto.setApprovedBy(null); + var context = mock(ConstraintValidatorContext.class); + var builder = mock(ConstraintValidatorContext.ConstraintViolationBuilder.class); + var nodeBuilder = + mock(ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext.class); + + when(context.buildConstraintViolationWithTemplate(anyString())).thenReturn(builder); + when(builder.addPropertyNode(anyString())).thenReturn(nodeBuilder); + + assertFalse(validator.isValid(dto, context)); + + verify(context).disableDefaultConstraintViolation(); + verify(builder).addPropertyNode("approvedBy"); + verify(nodeBuilder).addConstraintViolation(); + } + + @Test + public void isValidApprovedAllFieldsNotNullTrue() { + var dto = new CreateEditRequestDTO(); + dto.setStatus(EditRequestStatus.APPROVED); + dto.setApprovedAt(Timestamp.from(Instant.now())); + dto.setApprovedBy("Someone"); + var context = mock(ConstraintValidatorContext.class); + + assertTrue(validator.isValid(dto, context)); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceTest.java index fe637f42e..a86d7e72c 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/services/EditRequestServiceTest.java @@ -177,6 +177,7 @@ void performEditSuccess() throws InterruptedException { editRequest.setStatus(EditRequestStatus.PROCESSING); editRequest.setStartedAt(Timestamp.from(Instant.now())); editRequest.setSourceRecording(recording); + editRequest.setEditInstruction("{}"); when(editRequestRepository.findById(editRequest.getId())).thenReturn(Optional.of(editRequest)); when(editRequestRepository.findByIdNotLocked(editRequest.getId())).thenReturn(Optional.of(editRequest)); @@ -271,6 +272,7 @@ void createEditRequestSuccess() { appAccess.setUser(user); when(mockAuth.getAppAccess()).thenReturn(appAccess); + when(mockAuth.isAppUser()).thenReturn(true); SecurityContextHolder.getContext().setAuthentication(mockAuth); List instructions = new ArrayList<>(); @@ -279,12 +281,11 @@ void createEditRequestSuccess() { .end(120L) .build()); - var dto = CreateEditRequestDTO.builder() - .id(UUID.randomUUID()) - .sourceRecordingId(sourceRecording.getId()) - .status(EditRequestStatus.PENDING) - .editInstructions(instructions) - .build(); + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(sourceRecording.getId()); + dto.setStatus(EditRequestStatus.PENDING); + dto.setEditInstructions(instructions); when(recordingRepository.findByIdAndDeletedAtIsNull(sourceRecording.getId())) .thenReturn(Optional.of(sourceRecording)); @@ -321,12 +322,11 @@ void updateEditRequestSuccess() { .end(120L) .build()); - var dto = CreateEditRequestDTO.builder() - .id(UUID.randomUUID()) - .sourceRecordingId(sourceRecording.getId()) - .status(EditRequestStatus.PENDING) - .editInstructions(instructions) - .build(); + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(sourceRecording.getId()); + dto.setStatus(EditRequestStatus.PENDING); + dto.setEditInstructions(instructions); var editRequest = new EditRequest(); editRequest.setId(UUID.randomUUID()); @@ -368,12 +368,11 @@ void createEditRequestSourceRecordingNotFound() { .end(120L) .build()); - var dto = CreateEditRequestDTO.builder() - .id(UUID.randomUUID()) - .sourceRecordingId(UUID.randomUUID()) - .status(EditRequestStatus.PENDING) - .editInstructions(instructions) - .build(); + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(UUID.randomUUID()); + dto.setStatus(EditRequestStatus.PENDING); + dto.setEditInstructions(instructions); when(recordingRepository.findByIdAndDeletedAtIsNull(dto.getSourceRecordingId())) .thenReturn(Optional.empty()); @@ -411,12 +410,11 @@ void createEditRequestDurationIsNullError() { .end(120L) .build()); - var dto = CreateEditRequestDTO.builder() - .id(UUID.randomUUID()) - .sourceRecordingId(sourceRecording.getId()) - .status(EditRequestStatus.PENDING) - .editInstructions(instructions) - .build(); + var dto = new CreateEditRequestDTO(); + dto.setId(UUID.randomUUID()); + dto.setSourceRecordingId(sourceRecording.getId()); + dto.setStatus(EditRequestStatus.PENDING); + dto.setEditInstructions(instructions); when(recordingRepository.findByIdAndDeletedAtIsNull(sourceRecording.getId())) .thenReturn(Optional.of(sourceRecording)); @@ -657,7 +655,10 @@ void createRecordingSuccess() { assertThat(dto.getId()).isEqualTo(newRecordingId); assertThat(dto.getParentRecordingId()).isEqualTo(recording.getId()); assertThat(dto.getVersion()).isEqualTo(2); - assertThat(dto.getEditInstructions()).isEqualTo("{}"); + assertThat(dto.getEditInstructions()) + .isEqualTo("{\"editRequestId\":\"" + + editRequest.getId() + + "\",\"editInstructions\":{\"requestedInstructions\":null,\"ffmpegInstructions\":null}}"); assertThat(dto.getCaptureSessionId()).isEqualTo(captureSession.getId()); assertThat(dto.getFilename()).isEqualTo("index.mp4"); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/CleanupLiveEventsTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/CleanupLiveEventsTest.java index dedad5c91..b55145cab 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/CleanupLiveEventsTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/CleanupLiveEventsTest.java @@ -16,6 +16,7 @@ import uk.gov.hmcts.reform.preapi.dto.CaseDTO; import uk.gov.hmcts.reform.preapi.dto.CourtDTO; import uk.gov.hmcts.reform.preapi.dto.RecordingDTO; +import uk.gov.hmcts.reform.preapi.dto.RoleDTO; import uk.gov.hmcts.reform.preapi.dto.ShareBookingDTO; import uk.gov.hmcts.reform.preapi.dto.UserDTO; import uk.gov.hmcts.reform.preapi.dto.base.BaseAppAccessDTO; @@ -78,9 +79,12 @@ void beforeEach() { stopLiveEventNotifierFlowClient = mock(StopLiveEventNotifierFlowClient.class); emailServiceFactory = mock(EmailServiceFactory.class); + var role = new RoleDTO(); + role.setName("Super User"); var accessDto = mock(AccessDTO.class); var baseAppAccessDTO = mock(BaseAppAccessDTO.class); when(baseAppAccessDTO.getId()).thenReturn(UUID.randomUUID()); + when(baseAppAccessDTO.getRole()).thenReturn(role); when(userService.findByEmail(CRON_USER_EMAIL)).thenReturn(accessDto); when(accessDto.getAppAccess()).thenReturn(Set.of(baseAppAccessDTO)); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/ClosePendingCasesTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/ClosePendingCasesTest.java index 121af6dd7..fb84b1af7 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/ClosePendingCasesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/ClosePendingCasesTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import uk.gov.hmcts.reform.preapi.dto.AccessDTO; +import uk.gov.hmcts.reform.preapi.dto.RoleDTO; import uk.gov.hmcts.reform.preapi.dto.base.BaseAppAccessDTO; import uk.gov.hmcts.reform.preapi.security.authentication.UserAuthentication; import uk.gov.hmcts.reform.preapi.security.service.UserAuthenticationService; @@ -41,6 +42,9 @@ public void setUp() { var appAccess = new BaseAppAccessDTO(); appAccess.setId(UUID.randomUUID()); access.setAppAccess(Set.of(appAccess)); + var role = new RoleDTO(); + role.setName("Super User"); + appAccess.setRole(role); var userAuth = mock(UserAuthentication.class); when(userAuth.isAdmin()).thenReturn(true); when(userService.findByEmail(ROBOT_USER_EMAIL)).thenReturn(access); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/PerformEditRequestTest.java b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/PerformEditRequestTest.java index b4043cdd5..392a31a17 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/tasks/PerformEditRequestTest.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/tasks/PerformEditRequestTest.java @@ -8,6 +8,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import uk.gov.hmcts.reform.preapi.dto.AccessDTO; import uk.gov.hmcts.reform.preapi.dto.RecordingDTO; +import uk.gov.hmcts.reform.preapi.dto.RoleDTO; import uk.gov.hmcts.reform.preapi.dto.base.BaseAppAccessDTO; import uk.gov.hmcts.reform.preapi.entities.EditRequest; import uk.gov.hmcts.reform.preapi.enums.EditRequestStatus; @@ -54,8 +55,11 @@ void setUp() { CRON_USER_EMAIL ); + var role = new RoleDTO(); + role.setName("Super User"); var appAccess = new BaseAppAccessDTO(); appAccess.setId(UUID.randomUUID()); + appAccess.setRole(role); var access = new AccessDTO(); access.setAppAccess(Set.of(appAccess)); diff --git a/src/test/java/uk/gov/hmcts/reform/preapi/util/HelperFactory.java b/src/test/java/uk/gov/hmcts/reform/preapi/util/HelperFactory.java index c689832db..d4ab9b118 100644 --- a/src/test/java/uk/gov/hmcts/reform/preapi/util/HelperFactory.java +++ b/src/test/java/uk/gov/hmcts/reform/preapi/util/HelperFactory.java @@ -237,7 +237,11 @@ public static EditRequest createEditRequest(Recording sourceRecording, EditRequestStatus status, User createdBy, @Nullable Timestamp startedAt, - @Nullable Timestamp finishedAt) { + @Nullable Timestamp finishedAt, + @Nullable Boolean jointlyAgreed, + @Nullable String rejectionReason, + @Nullable Timestamp approvedAt, + @Nullable String approvedBy) { var editRequest = new EditRequest(); editRequest.setId(UUID.randomUUID()); editRequest.setSourceRecording(sourceRecording);