diff --git a/build.gradle b/build.gradle index 6f94eea212..5a07730d25 100644 --- a/build.gradle +++ b/build.gradle @@ -447,8 +447,8 @@ dependencies { implementation 'uk.gov.service.notify:notifications-java-client:5.2.1-RELEASE' - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.16' - implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.5.16' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.5.17' + implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.5.17' implementation group: 'io.vavr', name: 'vavr', version: '0.10.6' @@ -502,7 +502,7 @@ dependencies { dependencyManagement { dependencies { // Resolves CVE-2023-44487 - remove this block once azure-storage-blob pulls in latest version of netty - dependencySet(group: 'io.netty', version: '4.1.118.Final') { + dependencySet(group: 'io.netty', version: '4.1.119.Final') { entry 'netty-buffer' entry 'netty-codec' entry 'netty-codec-dns' diff --git a/charts/darts-api/Chart.yaml b/charts/darts-api/Chart.yaml index 9298f8f9df..0d0ede37b4 100644 --- a/charts/darts-api/Chart.yaml +++ b/charts/darts-api/Chart.yaml @@ -4,22 +4,22 @@ appVersion: "1.0" description: A Helm chart for darts-api App name: darts-api home: https://github.com/hmcts/darts-api -version: 0.0.99 +version: 0.0.100 maintainers: - name: HMCTS darts team dependencies: - name: java - version: 5.2.1 - repository: 'https://hmctspublic.azurecr.io/helm/v1/repo/' + version: 5.3.0 + repository: 'oci://hmctspublic.azurecr.io/helm' - name: function - version: 2.5.3 - repository: 'https://hmctspublic.azurecr.io/helm/v1/repo' + version: 2.6.0 + repository: 'oci://hmctspublic.azurecr.io/helm' - name: postgresql - version: 1.0.2 - repository: 'https://hmctspublic.azurecr.io/helm/v1/repo/' + version: 1.1.0 + repository: 'oci://hmctspublic.azurecr.io/helm' condition: postgresql.enabled - name: darts-portal - version: ~0.0.27 - repository: 'https://sdshmctspublic.azurecr.io/helm/v1/repo/' + version: ~0.0.28 + repository: 'oci://sdshmctspublic.azurecr.io/helm' condition: darts-portal.enabled diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerAddAudioMetadataIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerAddAudioMetadataIntTest.java index 64baf5892f..281609000a 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerAddAudioMetadataIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/AudioControllerAddAudioMetadataIntTest.java @@ -21,15 +21,21 @@ import uk.gov.hmcts.darts.audio.model.AddAudioMetadataRequestWithStorageGUID; import uk.gov.hmcts.darts.audio.model.Problem; import uk.gov.hmcts.darts.audio.service.AudioAsyncService; +import uk.gov.hmcts.darts.audit.api.AuditActivity; import uk.gov.hmcts.darts.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.AuditEntity; +import uk.gov.hmcts.darts.common.entity.CourtroomEntity; import uk.gov.hmcts.darts.common.entity.HearingEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; import uk.gov.hmcts.darts.common.entity.MediaLinkedCaseEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.common.enums.SecurityRoleEnum; +import uk.gov.hmcts.darts.common.repository.AuditRepository; import uk.gov.hmcts.darts.common.util.DateConverterUtil; import uk.gov.hmcts.darts.test.common.DataGenerator; import uk.gov.hmcts.darts.test.common.LogUtil; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; import uk.gov.hmcts.darts.testutils.IntegrationBase; import uk.gov.hmcts.darts.testutils.stubs.AuthorisationStub; import uk.gov.hmcts.darts.testutils.stubs.EventStub; @@ -53,6 +59,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -92,6 +99,9 @@ class AudioControllerAddAudioMetadataIntTest extends IntegrationBase { @Autowired private SuperAdminUserStub superAdminUserStub; + @Autowired + private AuditRepository auditRepository; + private String guid = UUID.randomUUID().toString(); private static final long END_FILE_DURATION = 1440; @@ -343,6 +353,158 @@ void addAudioReturnForbiddenError() throws Exception { JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } + @Test + void shouldHideIncomingMedia_whenIncomingMediaHasExistingVersionThatIsHiddenButHasNoExistingAdminAction() throws Exception { + // Given + superAdminUserStub.givenUserIsAuthorised(mockUserIdentity, SecurityRoleEnum.MID_TIER); + + CourtroomEntity existingCourtroom = PersistableFactory.getCourtroomTestData().someMinimalBuilderHolder().getBuilder() + .courthouse(PersistableFactory.getCourthouseTestData().someMinimal()) + .build() + .getEntity(); + dartsPersistence.save(existingCourtroom); + + final OffsetDateTime startAt = OffsetDateTime.parse("2024-10-10T10:00:00Z"); + final OffsetDateTime endAt = OffsetDateTime.parse("2024-10-10T10:15:00Z"); + MediaEntity initialMedia = PersistableFactory.getMediaTestData().someMinimalBuilderHolder() + .getBuilder() + .isHidden(true) + // The following attributes must align with the data that gets created by createAddAudioRequest(), so that we get a duplicate metadata scenario + .courtroom(existingCourtroom) + .channel(1) + .mediaFile("test") + .start(startAt) + .end(endAt) + .build() + .getEntity(); + dartsPersistence.save(initialMedia); + String chronicleId = initialMedia.getId().toString(); + initialMedia.setChronicleId(chronicleId); + dartsPersistence.save(initialMedia); + + AddAudioMetadataRequest request = createAddAudioRequest(startAt, + endAt, + existingCourtroom.getCourthouse().getCourthouseName(), + existingCourtroom.getName(), + AUDIO_BINARY_PAYLOAD_1); + + // When + mockMvc.perform( + post(ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + // Then, assert DB state + List allMedias = dartsDatabase.getMediaRepository().findAll(); + + List allVersions = allMedias.stream() + .filter(media -> chronicleId.equals(media.getChronicleId())) + .toList(); + assertEquals(2, allVersions.size()); + assertTrue(allVersions.stream().allMatch(MediaEntity::isHidden)); + + // Identify the newly added version + List newMediaVersions = allMedias.stream() + .filter(media -> String.valueOf(initialMedia.getId()).equals(media.getAntecedentId())) + .toList(); + assertEquals(1, newMediaVersions.size()); + MediaEntity newMediaVersion = newMediaVersions.getFirst(); + + Optional adminActionOptional = newMediaVersion.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + assertNull(adminAction.getTicketReference()); + assertEquals("Prior version had no admin action, so no details are available", adminAction.getComments()); + assertNull(adminAction.getObjectHiddenReason()); + + List hideAudio = dartsDatabase.getAuditRepository().findAll().stream() + .filter(audit -> AuditActivity.HIDE_AUDIO.getId().equals(audit.getAuditActivity().getId())) + .toList(); + assertEquals(1, hideAudio.size()); + } + + @Test + void shouldHideIncomingMediaAndCopyExistingAdminAction_whenIncomingMediaHasExistingVersionThatIsHiddenAndHasExistingAdminAction() throws Exception { + // Given + superAdminUserStub.givenUserIsAuthorised(mockUserIdentity, SecurityRoleEnum.MID_TIER); + + CourtroomEntity existingCourtroom = PersistableFactory.getCourtroomTestData().someMinimalBuilderHolder().getBuilder() + .courthouse(PersistableFactory.getCourthouseTestData().someMinimal()) + .build() + .getEntity(); + dartsPersistence.save(existingCourtroom); + + final OffsetDateTime startAt = OffsetDateTime.parse("2024-10-10T10:00:00Z"); + final OffsetDateTime endAt = OffsetDateTime.parse("2024-10-10T10:15:00Z"); + MediaEntity initialMedia = PersistableFactory.getMediaTestData().someMinimalBuilderHolder() + .getBuilder() + .isHidden(true) + // The following attributes must align with the data that gets created by createAddAudioRequest(), so that we get a duplicate metadata scenario + .courtroom(existingCourtroom) + .channel(1) + .mediaFile("test") + .start(startAt) + .end(endAt) + .build() + .getEntity(); + dartsPersistence.save(initialMedia); + + ObjectAdminActionEntity adminActionForInitialMedia = PersistableFactory.getObjectAdminActionTestData().someMinimalBuilderHolder() + .getBuilder() + .ticketReference("Some ticket ref") + .comments("Some comments") + .media(initialMedia) + .build() + .getEntity(); + dartsPersistence.save(adminActionForInitialMedia); + + String chronicleId = initialMedia.getId().toString(); + initialMedia.setChronicleId(chronicleId); + initialMedia.setObjectAdminAction(adminActionForInitialMedia); + dartsPersistence.save(initialMedia); + + AddAudioMetadataRequest request = createAddAudioRequest(startAt, + endAt, + existingCourtroom.getCourthouse().getCourthouseName(), + existingCourtroom.getName(), + AUDIO_BINARY_PAYLOAD_1); + + // When + mockMvc.perform( + post(ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + // Then, assert DB state + List allMedias = dartsDatabase.getMediaRepository().findAll(); + + List allVersions = allMedias.stream() + .filter(media -> chronicleId.equals(media.getChronicleId())) + .toList(); + assertEquals(2, allVersions.size()); + assertTrue(allVersions.stream().allMatch(MediaEntity::isHidden)); + + // Identify the newly added version + List newMediaVersions = allMedias.stream() + .filter(media -> String.valueOf(initialMedia.getId()).equals(media.getAntecedentId())) + .toList(); + assertEquals(1, newMediaVersions.size()); + MediaEntity newMediaVersion = newMediaVersions.getFirst(); + + Optional adminActionOptional = newMediaVersion.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + assertEquals(adminActionForInitialMedia.getTicketReference(), adminAction.getTicketReference()); + assertEquals(adminActionForInitialMedia.getComments(), adminAction.getComments()); + + List hideAudio = dartsDatabase.getAuditRepository().findAll().stream() + .filter(audit -> AuditActivity.HIDE_AUDIO.getId().equals(audit.getAuditActivity().getId())) + .toList(); + assertEquals(1, hideAudio.size()); + } + private AddAudioMetadataRequestWithStorageGUID createAddAudioRequest(OffsetDateTime startedAt, OffsetDateTime endedAt, String courthouse, String courtroom) throws IOException { return createAddAudioRequest(startedAt, endedAt, courthouse, courtroom, diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/MediaControllerAdminPostMediaIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/MediaControllerAdminPostMediaIntTest.java index 34cc2e80e8..ae02232b7d 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/MediaControllerAdminPostMediaIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/controller/MediaControllerAdminPostMediaIntTest.java @@ -4,6 +4,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import org.skyscreamer.jsonassert.Customization; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.skyscreamer.jsonassert.comparator.CustomComparator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -14,15 +18,19 @@ import uk.gov.hmcts.darts.audio.model.MediaHideRequest; import uk.gov.hmcts.darts.audio.model.MediaHideResponse; import uk.gov.hmcts.darts.audio.model.Problem; +import uk.gov.hmcts.darts.audit.api.AuditActivity; import uk.gov.hmcts.darts.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.AuditEntity; import uk.gov.hmcts.darts.common.entity.CourtroomEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.common.enums.HiddenReason; import uk.gov.hmcts.darts.common.enums.SecurityRoleEnum; import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; import uk.gov.hmcts.darts.common.repository.UserAccountRepository; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; import uk.gov.hmcts.darts.testutils.IntegrationBase; import uk.gov.hmcts.darts.testutils.stubs.MediaStub; import uk.gov.hmcts.darts.testutils.stubs.SuperAdminUserStub; @@ -33,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -348,4 +357,196 @@ void testMediaShowWithAdminActionFailure() throws Exception { Problem problemResponse = objectMapper.readValue(content, Problem.class); assertEquals(AudioApiError.MEDIA_SHOW_ACTION_PAYLOAD_INCORRECT_USAGE.getType(), problemResponse.getType()); } + + @Test + void shouldHideTargetedMediaAndAllOtherVersions_whenTargetedMediaHasChronicleId() throws Exception { + // Given + MediaEntity originalTargetedMedia = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .chronicleId("1000") + .isHidden(false) + .build() + .getEntity(); + MediaEntity originalOtherVersion = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .chronicleId("1000") + .isHidden(false) + .build() + .getEntity(); + dartsPersistence.saveAll(originalTargetedMedia, originalOtherVersion); + + AdminActionRequest adminActionRequest = new AdminActionRequest(); + adminActionRequest.setReasonId(HiddenReason.OTHER_HIDE.getId()); + adminActionRequest.setComments("some comment"); + adminActionRequest.setTicketReference("some ticket ref"); + + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + mediaHideRequest.setAdminAction(adminActionRequest); + mediaHideRequest.setIsHidden(true); + + UserAccountEntity clientUser = superAdminUserStub.givenUserIsAuthorised(userIdentity); + + // When + MvcResult mvcResult = mockMvc.perform(post(ENDPOINT_URL.replace( + MEDIA_ID_SUBSTITUTION_KEY, originalTargetedMedia.getId().toString())) + .header("Content-Type", "application/json") + .content(objectMapper.writeValueAsString(mediaHideRequest))) + .andExpect(status().is2xxSuccessful()) + .andReturn(); + + // Then + List adminActionsForTargetedMedia = objectAdminActionRepository.findAll().stream() + .filter(adminAction -> adminAction.getMedia().getId().equals(originalTargetedMedia.getId())) + .toList(); + assertEquals(1, adminActionsForTargetedMedia.size()); + ObjectAdminActionEntity adminActionEntity = adminActionsForTargetedMedia.getFirst(); + + JSONAssert.assertEquals( + """ + { + "id": 0, + "is_hidden": true, + "is_deleted": false, + "admin_action": { + "id": 0, + "reason_id": 0, + "hidden_by_id": 15000, + "hidden_at": "", + "is_marked_for_manual_deletion": false, + "ticket_reference": "some ticket ref", + "comments": "some comment" + } + } + """, + mvcResult.getResponse().getContentAsString(), + new CustomComparator( + JSONCompareMode.NON_EXTENSIBLE, + new Customization("id", (actual, expected) -> originalTargetedMedia.getId().equals(actual)), + new Customization("admin_action.id", (actual, expected) -> adminActionEntity.getId().equals(actual)), + new Customization("admin_action.reason_id", (actual, expected) -> HiddenReason.OTHER_HIDE.getId().equals(actual)), + new Customization("admin_action.hidden_by_id", (actual, expected) -> clientUser.getId().equals(actual)), + new Customization("admin_action.hidden_at", (actual, expected) -> isIsoDateTimeString((String) actual)) + ) + ); + + // And assert further DB state + getTransactionalUtil().executeInTransaction(() -> { + MediaEntity finalTargetedMedia = mediaRepository.findById(originalTargetedMedia.getId()) + .orElseThrow(); + assertTrue(finalTargetedMedia.isHidden()); + assertTrue(finalTargetedMedia.getObjectAdminAction().isPresent()); + + ObjectAdminActionEntity adminAction = finalTargetedMedia.getObjectAdminAction().get(); + assertEquals(HiddenReason.OTHER_HIDE.getId(), adminAction.getObjectHiddenReason().getId()); + assertEquals(originalTargetedMedia.getId(), adminAction.getMedia().getId()); + assertEquals(clientUser.getId(), adminAction.getHiddenBy().getId()); + assertNotNull(adminAction.getHiddenDateTime()); + assertFalse(adminAction.isMarkedForManualDeletion()); + assertNull(adminAction.getMarkedForManualDelBy()); + assertEquals("some ticket ref", adminAction.getTicketReference()); + assertEquals("some comment", adminAction.getComments()); + }); + + getTransactionalUtil().executeInTransaction(() -> { + MediaEntity finalOtherVersion = mediaRepository.findById(originalOtherVersion.getId()) + .orElseThrow(); + assertTrue(finalOtherVersion.isHidden()); + assertTrue(finalOtherVersion.getObjectAdminAction().isPresent()); + + ObjectAdminActionEntity adminAction = finalOtherVersion.getObjectAdminAction().get(); + assertEquals(HiddenReason.OTHER_HIDE.getId(), adminAction.getObjectHiddenReason().getId()); + assertEquals(originalOtherVersion.getId(), adminAction.getMedia().getId()); + assertEquals(clientUser.getId(), adminAction.getHiddenBy().getId()); + assertNotNull(adminAction.getHiddenDateTime()); + assertFalse(adminAction.isMarkedForManualDeletion()); + assertNull(adminAction.getMarkedForManualDelBy()); + assertEquals("some ticket ref", adminAction.getTicketReference()); + assertEquals("some comment", adminAction.getComments()); + }); + + List hideAudio = dartsDatabase.getAuditRepository().findAll().stream() + .filter(audit -> AuditActivity.HIDE_AUDIO.getId().equals(audit.getAuditActivity().getId())) + .toList(); + assertEquals(2, hideAudio.size()); + } + + @Test + void shouldUnHideTargetedMediaAndAllOtherVersions_whenTargetedMediaHasChronicleId() throws Exception { + // Given + superAdminUserStub.givenUserIsAuthorised(userIdentity); + + MediaEntity originalTargetedMedia = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .chronicleId("1000") + .isHidden(true) + .build() + .getEntity(); + MediaEntity originalOtherVersion = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .chronicleId("1000") + .isHidden(true) + .build() + .getEntity(); + dartsPersistence.saveAll(originalTargetedMedia, originalOtherVersion); + + ObjectAdminActionEntity targetedMediaAction = PersistableFactory.getObjectAdminActionTestData() + .someMinimalBuilder() + .media(originalTargetedMedia) + .build() + .getEntity(); + ObjectAdminActionEntity otherVersionAction = PersistableFactory.getObjectAdminActionTestData() + .someMinimalBuilder() + .media(originalOtherVersion) + .build() + .getEntity(); + dartsPersistence.saveAll(targetedMediaAction, otherVersionAction); + + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + mediaHideRequest.setIsHidden(false); + + // When + MvcResult mvcResult = mockMvc.perform(post(ENDPOINT_URL.replace( + MEDIA_ID_SUBSTITUTION_KEY, originalTargetedMedia.getId().toString())) + .header("Content-Type", "application/json") + .content(objectMapper.writeValueAsString(mediaHideRequest))) + .andExpect(status().is2xxSuccessful()) + .andReturn(); + + // Then + JSONAssert.assertEquals( + """ + { + "id": 0, + "is_hidden": false, + "is_deleted": false + } + """, + mvcResult.getResponse().getContentAsString(), + new CustomComparator( + JSONCompareMode.NON_EXTENSIBLE, + new Customization("id", (actual, expected) -> actual.equals(originalTargetedMedia.getId())) + ) + ); + + // And assert DB state + getTransactionalUtil().executeInTransaction(() -> { + MediaEntity finalTargetedMedia = mediaRepository.findById(originalTargetedMedia.getId()) + .orElseThrow(); + assertFalse(finalTargetedMedia.isHidden()); + assertFalse(finalTargetedMedia.getObjectAdminAction().isPresent()); + }); + + getTransactionalUtil().executeInTransaction(() -> { + MediaEntity finalOtherVersion = mediaRepository.findById(originalOtherVersion.getId()) + .orElseThrow(); + assertFalse(finalOtherVersion.isHidden()); + assertFalse(finalOtherVersion.getObjectAdminAction().isPresent()); + }); + + List hideAudio = dartsDatabase.getAuditRepository().findAll().stream() + .filter(audit -> AuditActivity.UNHIDE_AUDIO.getId().equals(audit.getAuditActivity().getId())) + .toList(); + assertEquals(2, hideAudio.size()); + } + } \ No newline at end of file diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceGivenBuilder.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceGivenBuilder.java index 735d9c72b3..0a464c74f0 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceGivenBuilder.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceGivenBuilder.java @@ -11,11 +11,8 @@ import uk.gov.hmcts.darts.test.common.data.ExternalObjectDirectoryTestData; import uk.gov.hmcts.darts.test.common.data.PersistableFactory; import uk.gov.hmcts.darts.test.common.data.builder.TestExternalObjectDirectoryEntity; -import uk.gov.hmcts.darts.test.common.data.builder.TestMediaEntity; import uk.gov.hmcts.darts.testutils.stubs.DartsPersistence; -import java.time.OffsetDateTime; - import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.UNSTRUCTURED; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.STORED; @@ -41,8 +38,6 @@ public class AudioTransformationServiceGivenBuilder { private MediaEntity mediaEntity2; private MediaEntity mediaEntity3; private MediaEntity mediaEntity4; - private static final OffsetDateTime MEDIA_START_TIME = OffsetDateTime.parse("2023-01-01T12:00:00Z"); - private static final OffsetDateTime MEDIA_END_TIME = MEDIA_START_TIME.plusHours(1); public void setupTest() { hearingEntityWithMedia1 = PersistableFactory.getHearingTestData().someMinimalHearing(); @@ -50,19 +45,23 @@ public void setupTest() { hearingEntityWithMedia3 = PersistableFactory.getHearingTestData().someMinimalHearing(); hearingEntityWithMedia4 = PersistableFactory.getHearingTestData().someMinimalHearing(); hearingEntityWithoutMedia = PersistableFactory.getHearingTestData().someMinimalHearing(); - TestMediaEntity.TestMediaBuilderRetrieve mediaTestData1 = getMediaTestData().someMinimalBuilderHolder(); - TestMediaEntity.TestMediaBuilderRetrieve mediaTestData2 = getMediaTestData().someMinimalBuilderHolder(); - TestMediaEntity.TestMediaBuilderRetrieve mediaTestData3 = getMediaTestData().someMinimalBuilderHolder(); - TestMediaEntity.TestMediaBuilderRetrieve mediaTestData4 = getMediaTestData().someMinimalBuilderHolder(); - - int channel = 1; - mediaTestData1.getBuilder().channel(1); - mediaTestData4.getBuilder().isHidden(true).channel(channel); - - mediaEntity1 = mediaTestData1.build().getEntity(); - mediaEntity2 = mediaTestData2.build().getEntity(); - mediaEntity3 = mediaTestData3.build().getEntity(); - mediaEntity4 = mediaTestData4.build().getEntity(); + mediaEntity1 = getMediaTestData().someMinimalBuilder() + .isCurrent(true) + .build() + .getEntity(); + mediaEntity2 = getMediaTestData().someMinimalBuilder() + .isCurrent(true) + .build() + .getEntity(); + mediaEntity3 = getMediaTestData().someMinimalBuilder() + .isCurrent(true) + .build() + .getEntity(); + mediaEntity4 = getMediaTestData().someMinimalBuilder() + .isCurrent(true) + .isHidden(true) + .build() + .getEntity(); hearingEntityWithMedia1.addMedia(mediaEntity1); hearingEntityWithMedia1.addMedia(mediaEntity2); @@ -71,9 +70,9 @@ public void setupTest() { dartsPersistence.save(hearingEntityWithMedia1); dartsPersistence.save(hearingEntityWithMedia2); + dartsPersistence.save(hearingEntityWithMedia3); dartsPersistence.save(hearingEntityWithMedia4); dartsPersistence.save(hearingEntityWithoutMedia); - dartsPersistence.save(mediaEntity3); } public ExternalObjectDirectoryEntity externalObjectDirForMedia(MediaEntity mediaEntity) { @@ -83,8 +82,8 @@ public ExternalObjectDirectoryEntity externalObjectDirForMedia(MediaEntity media retrieve.getBuilder().media(mediaEntity).status(dartsDatabase .getObjectRecordStatusRepository() .getReferenceById(STORED.getId())) - .externalLocationType(dartsDatabase - .getExternalLocationTypeRepository().getReferenceById(UNSTRUCTURED.getId())); + .externalLocationType(dartsDatabase + .getExternalLocationTypeRepository().getReferenceById(UNSTRUCTURED.getId())); return dartsDatabase.save(retrieve.build().getEntity()); } } \ No newline at end of file diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceTest.java index c1d3c73a45..10e8b24dc1 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/service/AudioTransformationServiceTest.java @@ -5,6 +5,7 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; import uk.gov.hmcts.darts.audio.config.AudioConfigurationProperties; import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.service.FileOperationService; import uk.gov.hmcts.darts.testutils.IntegrationBase; import uk.gov.hmcts.darts.testutils.stubs.DartsPersistence; @@ -42,6 +43,9 @@ class AudioTransformationServiceTest extends IntegrationBase { @Autowired DartsPersistence dartsPersistence; + @Autowired + private MediaRepository mediaRepository; + @Test void getMediaByHearingIdShouldReturnExpectedMediaEntitiesWhenHearingIdHasRelatedMedia() { given.setupTest(); diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/casedocument/service/CourtCaseDocumentMapperIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/casedocument/service/CourtCaseDocumentMapperIntTest.java index aff1445239..f99230b4b5 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/casedocument/service/CourtCaseDocumentMapperIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/casedocument/service/CourtCaseDocumentMapperIntTest.java @@ -354,31 +354,31 @@ void mapToCourtCaseDocument() { cc.getHearings().get(0).getMediaList().get(0).getRetainUntilTs()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getId()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getAnnotationDocument()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getAnnotationDocument().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getAnnotationDocument().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getCaseDocument()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getCaseDocument().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getCaseDocument().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getMedia()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getMedia().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getMedia().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getTranscriptionDocument()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getTranscriptionDocument().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getTranscriptionDocument().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getHiddenBy()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getHiddenBy().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getHiddenBy().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getHiddenDateTime()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getHiddenDateTime()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getHiddenDateTime()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).isMarkedForManualDeletion()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).isMarkedForManualDeletion()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).isMarkedForManualDeletion()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getMarkedForManualDelBy()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getMarkedForManualDelBy().getId()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getMarkedForManualDelBy().getId()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getMarkedForManualDelDateTime()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getMarkedForManualDelDateTime()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getMarkedForManualDelDateTime()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getTicketReference()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getTicketReference()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getTicketReference()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getComments()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getComments()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getComments()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getAdminActionReasons().get(0).getObjectHiddenReason()).isNotNull().isEqualTo( - cc.getHearings().get(0).getMediaList().get(0).getAdminActionReasons().get(0).getObjectHiddenReason()), + cc.getHearings().get(0).getMediaList().get(0).getObjectAdminActions().get(0).getObjectHiddenReason()), () -> assertThat(doc.getHearings().get(0).getMedias().get(0).getExternalObjectDirectories().get(0).getId()).isNotNull().isEqualTo( mediaEodEntity.getId()), diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/common/repository/MediaRepositoryTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/common/repository/MediaRepositoryTest.java new file mode 100644 index 0000000000..3bf98f5d88 --- /dev/null +++ b/src/integrationTest/java/uk/gov/hmcts/darts/common/repository/MediaRepositoryTest.java @@ -0,0 +1,93 @@ +package uk.gov.hmcts.darts.common.repository; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.test.common.data.MediaTestData; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; +import uk.gov.hmcts.darts.testutils.PostgresIntegrationBase; +import uk.gov.hmcts.darts.testutils.stubs.DartsPersistence; + +import java.time.OffsetDateTime; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.collection.IsEmptyCollection.empty; + +public class MediaRepositoryTest extends PostgresIntegrationBase { + + @Autowired + private MediaRepository mediaRepository; + + @Autowired + private DartsPersistence dartsPersistence; + + @Nested + class FindAllByChronicleIdTest { + + @BeforeEach + void setUp() { + // Just some standing data + MediaEntity media = PersistableFactory.getMediaTestData().someMinimalBuilder() + .chronicleId("1000") + .build() + .getEntity(); + + dartsPersistence.save(media); + } + + @Test + void shouldReturnEmptyList_whenThereAreNoOtherVersions() { + // Given + final String chronicleIdForWhichNoRecordsExist = "0"; + + // When + List allByChronicleId = mediaRepository.findAllByChronicleId(chronicleIdForWhichNoRecordsExist); + + // Then + assertThat(allByChronicleId, empty()); + } + + @Test + void shouldReturnTwoMedias_whenThereAreTwoOtherVersions() { + // Given + MediaTestData mediaTestData = PersistableFactory.getMediaTestData(); + + final String someCommonChronicleId = "2000"; + + final OffsetDateTime someStartTime = OffsetDateTime.parse("2025-01-01T00:00:00Z"); + MediaEntity media1 = mediaTestData.someMinimalBuilder() + .chronicleId(someCommonChronicleId) + .start(someStartTime) + .build() + .getEntity(); + dartsPersistence.save(media1); + + final OffsetDateTime someLaterStartTime = someStartTime.plusDays(1); + MediaEntity media2 = mediaTestData.someMinimalBuilder() + .chronicleId(someCommonChronicleId) + .start(someLaterStartTime) + .build() + .getEntity(); + dartsPersistence.save(media2); + + // When + List foundMedias = mediaRepository.findAllByChronicleId(someCommonChronicleId); + + // Then + assertThat(foundMedias, hasSize(2)); + + MediaEntity firstFoundMedia = foundMedias.get(0); + assertThat(firstFoundMedia.getId(), equalTo(media1.getId())); + + MediaEntity secondFoundMedia = foundMedias.get(1); + assertThat(secondFoundMedia.getId(), equalTo(media2.getId())); + } + + } + +} diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/courthouse/AudioAuditTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/courthouse/AudioAuditTest.java index edc8cb8e15..f71f3248ca 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/courthouse/AudioAuditTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/courthouse/AudioAuditTest.java @@ -3,13 +3,10 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import uk.gov.hmcts.darts.audio.entity.MediaRequestEntity; -import uk.gov.hmcts.darts.audio.model.AdminActionRequest; -import uk.gov.hmcts.darts.audio.model.MediaHideRequest; import uk.gov.hmcts.darts.audio.service.MediaRequestService; import uk.gov.hmcts.darts.audiorequests.model.MediaPatchRequest; import uk.gov.hmcts.darts.common.entity.AuditEntity; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; -import uk.gov.hmcts.darts.test.common.data.PersistableFactory; import uk.gov.hmcts.darts.testutils.GivenBuilder; import uk.gov.hmcts.darts.testutils.IntegrationBase; import uk.gov.hmcts.darts.testutils.stubs.EntityGraphPersistence; @@ -52,25 +49,6 @@ void performsStandardAndAdvancedAuditsWhenAudioOwnershipIsChanged() { assertThat(mediaRequestRevisions.getLatestRevision().getMetadata().getRevisionType()).isEqualTo(UPDATE); } - @Test - void performsStandardAuditWhenAudioIsChangedToHidden() { - var activeUser = given.anAuthenticatedUserWithGlobalAccessAndRole(SUPER_ADMIN); - var media = PersistableFactory.getMediaTestData().someMinimalMedia(); - media.setHidden(false); - dartsDatabase.save(media.getCourtroom().getCourthouse()); - dartsDatabase.save(media.getCourtroom()); - dartsDatabase.save(media); - - mediaRequestService.adminHideOrShowMediaById( - media.getId(), - new MediaHideRequest() - .isHidden(true) - .adminAction(new AdminActionRequest().reasonId(4))); - - var hidingAudioAuditActivity = findAuditActivity("Hiding Audio", dartsDatabase.findAudits()); - assertThat(hidingAudioAuditActivity.getUser().getId()).isEqualTo(activeUser.getId()); - } - private AuditEntity findAuditActivity(String activity, List audits) { return audits.stream() .filter(audit -> activity.equals(audit.getAuditActivity().getName())) diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/IntegrationBase.java b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/IntegrationBase.java index 64f0d8f08c..0428ea1f7d 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/IntegrationBase.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/IntegrationBase.java @@ -1,6 +1,7 @@ package uk.gov.hmcts.darts.testutils; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -31,6 +32,9 @@ import uk.gov.hmcts.darts.testutils.stubs.wiremock.TokenStub; import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.List; import java.util.Optional; @@ -88,6 +92,7 @@ public class IntegrationBase { @Autowired protected ObjectMapper objectMapper; @Autowired + @Getter protected TransactionalUtil transactionalUtil; @Autowired private List automatedOnDemandTask; @@ -177,4 +182,16 @@ protected void waitForOnDemandToComplete() { protected void anAuthenticatedUserFor(String userEmail) { GivenBuilder.anAuthenticatedUserFor(userEmail, dartsDatabase.getUserAccountRepository()); } + + // UselessOperationOnImmutable suppression: We don't care about the return value of parse(), we just want to know whether it throws an exception + @SuppressWarnings("PMD.UselessOperationOnImmutable") + protected boolean isIsoDateTimeString(String string) { + try { + LocalDateTime.parse(string, DateTimeFormatter.ISO_DATE_TIME); + } catch (DateTimeParseException e) { + return false; + } + return true; + } + } \ No newline at end of file diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsPersistence.java b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsPersistence.java index 7591b18ab7..0091d1f8a0 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsPersistence.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsPersistence.java @@ -348,6 +348,19 @@ public TranscriptionDocumentEntity save(TranscriptionDocumentEntity transcriptio @Transactional @SuppressWarnings("PMD.AvoidReassigningParameters") public ObjectAdminActionEntity save(ObjectAdminActionEntity adminAction) { + if (adminAction.getAnnotationDocument() != null) { + save(adminAction.getAnnotationDocument()); + } + if (adminAction.getCaseDocument() != null) { + save(adminAction.getCaseDocument()); + } + if (adminAction.getMedia() != null) { + save(adminAction.getMedia()); + } + if (adminAction.getTranscriptionDocument() != null) { + save(adminAction.getTranscriptionDocument()); + } + return objectAdminActionRepository.save(adminAction); } @@ -720,12 +733,21 @@ public void saveAll(ExternalObjectDirectoryEntity... externalObjectDirectoryEnti stream(externalObjectDirectoryEntities).forEach(this::save); } + @Transactional + public void saveAll(MediaEntity... mediaEntities) { + stream(mediaEntities).forEach(this::save); + } + + @Transactional + public void saveAll(ObjectAdminActionEntity... adminActionEntities) { + stream(adminActionEntities).forEach(this::save); + } + @Transactional public void saveAll(List externalObjectDirectoryEntities) { externalObjectDirectoryEntities.forEach(this::save); } - private void saveMediaList(List mediaList) { mediaList.forEach(media -> { if (media.getId() == null) { diff --git a/src/main/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponent.java b/src/main/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponent.java new file mode 100644 index 0000000000..74c07180fc --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponent.java @@ -0,0 +1,104 @@ +package uk.gov.hmcts.darts.audio.component.impl; + +import jakarta.transaction.Transactional; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.darts.audit.api.AuditApi; +import uk.gov.hmcts.darts.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.helper.CurrentTimeHelper; +import uk.gov.hmcts.darts.common.repository.MediaRepository; +import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; + +import java.util.Collections; +import java.util.List; + +import static uk.gov.hmcts.darts.audit.api.AuditActivity.HIDE_AUDIO; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ApplyAdminActionComponent { + + private final UserIdentity userIdentity; + private final CurrentTimeHelper currentTimeHelper; + private final RemoveAdminActionComponent removeAdminActionComponent; + + private final MediaRepository mediaRepository; + private final ObjectAdminActionRepository adminActionRepository; + + private final AuditApi auditApi; + + private static final String AUDIT_TEMPLATE = "Media id: %d, Ticket ref: %s"; + + public record AdminActionProperties(String ticketReference, String comments, ObjectHiddenReasonEntity hiddenReason) {} + + @Transactional + public List applyAdminActionToAllVersions(@NonNull MediaEntity targetedMedia, + @NonNull AdminActionProperties adminActionProperties) { + + List allMediaVersions; + final String ticketReference = adminActionProperties.ticketReference(); + if (StringUtils.isBlank(targetedMedia.getChronicleId())) { + log.debug("Attempting to apply admin action with ticket ref {} to non-versioned media with id {}", + ticketReference, + targetedMedia.getId()); + allMediaVersions = Collections.singletonList(targetedMedia); + } else { + log.debug("Attempting to apply admin action with ticket ref {} to all versioned medias with chronicle id {}", + ticketReference, + targetedMedia.getChronicleId()); + allMediaVersions = mediaRepository.findAllByChronicleId(targetedMedia.getChronicleId()); + } + + return applyAdminActionTo(allMediaVersions, adminActionProperties); + } + + @Transactional + public List applyAdminActionTo(@NonNull List mediaVersions, + @NonNull AdminActionProperties adminActionProperties) { + // We need to first remove any existing admin actions so that we can link new actions reflecting the details in the incoming adminActionProperties + removeAdminActionComponent.removeAdminActionFrom(mediaVersions); + + final String ticketReference = adminActionProperties.ticketReference(); + UserAccountEntity currentUser = userIdentity.getUserAccount(); + for (MediaEntity media : mediaVersions) { + auditApi.record(HIDE_AUDIO, AUDIT_TEMPLATE.formatted(media.getId(), ticketReference)); + + ObjectAdminActionEntity adminAction = createAdminAction(ticketReference, + adminActionProperties.comments(), + adminActionProperties.hiddenReason(), + currentUser); + adminAction.setMedia(media); + adminActionRepository.saveAndFlush(adminAction); + + media.setObjectAdminAction(adminAction); + media.setHidden(true); + mediaRepository.saveAndFlush(media); + } + + return mediaVersions; + } + + private ObjectAdminActionEntity createAdminAction(String ticketReference, + String comments, + ObjectHiddenReasonEntity hiddenReason, + UserAccountEntity userAccount) { + var objectAdminActionEntity = new ObjectAdminActionEntity(); + objectAdminActionEntity.setTicketReference(ticketReference); + objectAdminActionEntity.setComments(comments); + objectAdminActionEntity.setObjectHiddenReason(hiddenReason); + objectAdminActionEntity.setHiddenBy(userAccount); + objectAdminActionEntity.setHiddenDateTime(currentTimeHelper.currentOffsetDateTime()); + objectAdminActionEntity.setMarkedForManualDeletion(false); + + return objectAdminActionEntity; + } + +} diff --git a/src/main/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponent.java b/src/main/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponent.java new file mode 100644 index 0000000000..d12560ea04 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponent.java @@ -0,0 +1,86 @@ +package uk.gov.hmcts.darts.audio.component.impl; + +import jakarta.transaction.Transactional; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.darts.audit.api.AuditActivity; +import uk.gov.hmcts.darts.audit.api.AuditApi; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.repository.MediaRepository; +import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class RemoveAdminActionComponent { + + private final MediaRepository mediaRepository; + private final ObjectAdminActionRepository adminActionRepository; + + private final AuditApi auditApi; + + public static final String AUDIT_TEMPLATE = "Media id: %d, Ticket ref: %s, Comments: %s"; + + @Transactional + public List removeAdminActionFromAllVersions(@NonNull MediaEntity targetedMedia) { + List allMediaVersions; + if (StringUtils.isBlank(targetedMedia.getChronicleId())) { + log.debug("Attempting to remove all admin actions from non-versioned media with id {}", + targetedMedia.getId()); + allMediaVersions = Collections.singletonList(targetedMedia); + } else { + log.debug("Attempting to remove all admin actions from all versioned medias with chronicle id {}", + targetedMedia.getChronicleId()); + allMediaVersions = mediaRepository.findAllByChronicleId(targetedMedia.getChronicleId()); + } + return removeAdminActionFrom(allMediaVersions); + } + + @Transactional + public List removeAdminActionFrom(@NonNull List mediaVersions) { + Set uniqueChronicleIds = mediaVersions.stream() + .map(MediaEntity::getChronicleId) + .collect(Collectors.toSet()); + if (uniqueChronicleIds.size() != 1) { + throw new IllegalStateException("All media versions must have the same chronicle id"); + } + + for (MediaEntity media : mediaVersions) { + log.debug("Attempting to remove all admin actions from media id {}", + media.getId()); + Optional adminActionOptional = media.getObjectAdminAction(); + if (media.isHidden() || adminActionOptional.isPresent()) { + String comments = null; + String ticketReference = null; + if (adminActionOptional.isPresent()) { + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + comments = adminAction.getComments(); + ticketReference = adminAction.getTicketReference(); + } + + auditApi.record(AuditActivity.UNHIDE_AUDIO, AUDIT_TEMPLATE.formatted(media.getId(), ticketReference, comments)); + + media.setObjectAdminActions(new ArrayList<>()); + adminActionOptional.ifPresent(objectAdminActionEntity -> + adminActionRepository.deleteById(objectAdminActionEntity.getId())); + + media.setHidden(false); + mediaRepository.saveAndFlush(media); + } + } + + return mediaVersions; + } + +} diff --git a/src/main/java/uk/gov/hmcts/darts/audio/controller/AudioController.java b/src/main/java/uk/gov/hmcts/darts/audio/controller/AudioController.java index b048081fa6..0fab69eecc 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/controller/AudioController.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/controller/AudioController.java @@ -129,7 +129,6 @@ public ResponseEntity adminGetTransformedMedia(Inte var transformedMedia = mediaRequestService.getTransformedMediaById(transformedMediaId); GetTransformedMediaResponse response = transformedMediaMapper.mapToGetTransformedMediaResponse(transformedMedia); return new ResponseEntity<>(response, HttpStatus.OK); - } @Override @@ -146,7 +145,7 @@ public ResponseEntity> getAdminMedias(Integer tr @SecurityRequirement(name = SECURITY_SCHEMES_BEARER_AUTH) @Authorisation(contextId = ANY_ENTITY_ID, globalAccessSecurityRoles = {SUPER_ADMIN}) public ResponseEntity postAdminHideMediaId(Integer mediaId, MediaHideRequest mediaHideRequest) { - MediaHideResponse audioResponse = mediaRequestService.adminHideOrShowMediaById(mediaId, mediaHideRequest); + MediaHideResponse audioResponse = adminMediaService.adminHideOrShowMediaById(mediaId, mediaHideRequest); return new ResponseEntity<>(audioResponse, HttpStatus.OK); } diff --git a/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMarkedForDeletionMapper.java b/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMarkedForDeletionMapper.java index 7b61e73637..1ec038432f 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMarkedForDeletionMapper.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMarkedForDeletionMapper.java @@ -22,7 +22,7 @@ public interface AdminMarkedForDeletionMapper { @Mapping(target = "channel", source = "channel"), @Mapping(target = "courthouse", source = "courtroom.courthouse"), @Mapping(target = "courtroom", source = "courtroom"), - @Mapping(target = "adminAction", source = "adminActionReasons") + @Mapping(target = "adminAction", source = "objectAdminActions") }) PostAdminMediasMarkedForDeletionItem toApiModel(MediaEntity mediaEntity); diff --git a/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMediaMapper.java b/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMediaMapper.java index 39d9d70984..81bd25a3ab 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMediaMapper.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/mapper/AdminMediaMapper.java @@ -30,7 +30,7 @@ public interface AdminMediaMapper { @Mapping(target = "mediaStatus", source = "mediaStatus"), @Mapping(target = "isHidden", source = "hidden"), @Mapping(target = "isDeleted", source = "deleted"), - @Mapping(target = "adminAction", source = "adminActionReasons"), + @Mapping(target = "adminAction", source = "objectAdminActions"), @Mapping(target = "version", source = "legacyVersionLabel"), @Mapping(target = "chronicleId", source = "chronicleId"), @Mapping(target = "antecedentId", source = "antecedentId"), diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/AdminMediaService.java b/src/main/java/uk/gov/hmcts/darts/audio/service/AdminMediaService.java index ec931ba7f7..13ba0e2afa 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/AdminMediaService.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/AdminMediaService.java @@ -4,6 +4,8 @@ import uk.gov.hmcts.darts.audio.model.GetAdminMediaResponseItem; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionItem; import uk.gov.hmcts.darts.audio.model.MediaApproveMarkedForDeletionResponse; +import uk.gov.hmcts.darts.audio.model.MediaHideRequest; +import uk.gov.hmcts.darts.audio.model.MediaHideResponse; import uk.gov.hmcts.darts.audio.model.PostAdminMediasSearchRequest; import uk.gov.hmcts.darts.audio.model.PostAdminMediasSearchResponseItem; @@ -23,6 +25,8 @@ default List filterMediasWithTransformedMediaId(Integ List performAdminMediasSearchPost(PostAdminMediasSearchRequest adminMediasSearchRequest); + MediaHideResponse adminHideOrShowMediaById(Integer mediaId, MediaHideRequest mediaHideRequest); + List getMediasMarkedForDeletion(); MediaApproveMarkedForDeletionResponse adminApproveMediaMarkedForDeletion(Integer mediaId); diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/MediaRequestService.java b/src/main/java/uk/gov/hmcts/darts/audio/service/MediaRequestService.java index 12a6bd3b7b..de7799da4b 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/MediaRequestService.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/MediaRequestService.java @@ -2,8 +2,6 @@ import uk.gov.hmcts.darts.audio.entity.MediaRequestEntity; import uk.gov.hmcts.darts.audio.enums.MediaRequestStatus; -import uk.gov.hmcts.darts.audio.model.MediaHideRequest; -import uk.gov.hmcts.darts.audio.model.MediaHideResponse; import uk.gov.hmcts.darts.audiorequests.model.AudioNonAccessedResponse; import uk.gov.hmcts.darts.audiorequests.model.AudioRequestDetails; import uk.gov.hmcts.darts.audiorequests.model.GetAudioRequestResponse; @@ -60,6 +58,4 @@ public interface MediaRequestService { MediaPatchResponse patchMediaRequest(Integer mediaRequestId, MediaPatchRequest request); - MediaHideResponse adminHideOrShowMediaById(Integer mediaId, MediaHideRequest mediaHideRequest); - } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java index a00bfe55b8..cdbba18915 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImpl.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import uk.gov.hmcts.darts.audio.component.impl.ApplyAdminActionComponent; +import uk.gov.hmcts.darts.audio.component.impl.RemoveAdminActionComponent; import uk.gov.hmcts.darts.audio.entity.MediaRequestEntity; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.helper.PostAdminMediasSearchHelper; @@ -17,17 +19,21 @@ import uk.gov.hmcts.darts.audio.mapper.GetAdminMediaResponseMapper; import uk.gov.hmcts.darts.audio.mapper.ObjectActionMapper; import uk.gov.hmcts.darts.audio.mapper.PostAdminMediaSearchResponseMapper; +import uk.gov.hmcts.darts.audio.model.AdminActionRequest; import uk.gov.hmcts.darts.audio.model.AdminMediaResponse; import uk.gov.hmcts.darts.audio.model.GetAdminMediaResponseItem; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionAdminAction; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionItem; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionMediaItem; import uk.gov.hmcts.darts.audio.model.MediaApproveMarkedForDeletionResponse; +import uk.gov.hmcts.darts.audio.model.MediaHideRequest; +import uk.gov.hmcts.darts.audio.model.MediaHideResponse; import uk.gov.hmcts.darts.audio.model.MediaSearchData; import uk.gov.hmcts.darts.audio.model.PostAdminMediasSearchRequest; import uk.gov.hmcts.darts.audio.model.PostAdminMediasSearchResponseItem; import uk.gov.hmcts.darts.audio.service.AdminMediaService; import uk.gov.hmcts.darts.audio.validation.MediaApproveMarkForDeletionValidator; +import uk.gov.hmcts.darts.audio.validation.MediaHideOrShowValidator; import uk.gov.hmcts.darts.audio.validation.SearchMediaValidator; import uk.gov.hmcts.darts.audit.api.AuditActivity; import uk.gov.hmcts.darts.audit.api.AuditApi; @@ -35,13 +41,16 @@ import uk.gov.hmcts.darts.common.entity.HearingEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; import uk.gov.hmcts.darts.common.entity.TransformedMediaEntity; import uk.gov.hmcts.darts.common.exception.CommonApiError; import uk.gov.hmcts.darts.common.exception.DartsApiException; import uk.gov.hmcts.darts.common.helper.CurrentTimeHelper; import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; +import uk.gov.hmcts.darts.common.repository.ObjectHiddenReasonRepository; import uk.gov.hmcts.darts.common.repository.TransformedMediaRepository; +import uk.gov.hmcts.darts.common.validation.IdRequest; import java.time.OffsetDateTime; import java.util.ArrayList; @@ -55,22 +64,28 @@ @RequiredArgsConstructor public class AdminMediaServiceImpl implements AdminMediaService { - private final MediaRepository mediaRepository; - private final AdminMediaMapper adminMediaMapper; - private final PostAdminMediasSearchHelper postAdminMediasSearchHelper; private final SearchMediaValidator searchMediaValidator; - private final TransformedMediaRepository transformedMediaRepository; - private final ObjectAdminActionRepository objectAdminActionRepository; private final MediaApproveMarkForDeletionValidator mediaApproveMarkForDeletionValidator; + private final MediaHideOrShowValidator mediaHideOrShowValidator; + + private final PostAdminMediasSearchHelper postAdminMediasSearchHelper; private final UserIdentity userIdentity; private final CurrentTimeHelper currentTimeHelper; - private final AuditApi auditApi; - private final AdminMarkedForDeletionMapper adminMarkedForDeletionMapper; + private final ApplyAdminActionComponent applyAdminActionComponent; + private final RemoveAdminActionComponent removeAdminActionComponent; + private final AdminMediaMapper adminMediaMapper; + private final AdminMarkedForDeletionMapper adminMarkedForDeletionMapper; private final CourthouseMapper courthouseMapper; private final CourtroomMapper courtroomMapper; private final ObjectActionMapper objectActionMapper; + private final MediaRepository mediaRepository; + private final TransformedMediaRepository transformedMediaRepository; + private final ObjectAdminActionRepository objectAdminActionRepository; + private final ObjectHiddenReasonRepository hiddenReasonRepository; + + private final AuditApi auditApi; @Value("${darts.audio.admin-search.max-results}") private Integer adminSearchMaxResults; @@ -137,6 +152,29 @@ public List filterMedias(Integer transformedMediaId, .collect(Collectors.toList()); } + @Transactional + @Override + public MediaHideResponse adminHideOrShowMediaById(Integer mediaId, MediaHideRequest mediaHideRequest) { + IdRequest request = new IdRequest<>(mediaHideRequest, mediaId); + mediaHideOrShowValidator.validate(request); + + final MediaEntity targetedMedia = mediaRepository.findByIdIncludeDeleted(mediaId) + .orElseThrow(() -> new IllegalStateException("Media not found, expected this to be pre-validated")); + + boolean isToBeHidden = mediaHideRequest.getIsHidden(); + if (isToBeHidden) { + AdminActionRequest adminActionRequest = mediaHideRequest.getAdminAction(); + applyAdminActionComponent.applyAdminActionToAllVersions(targetedMedia, + mapToAdminActionProperties(adminActionRequest)); + ObjectAdminActionEntity adminActionForTargetedMedia = objectAdminActionRepository.findByMedia_Id(targetedMedia.getId()) + .getFirst(); + return GetAdminMediaResponseMapper.mapHideOrShowResponse(targetedMedia, adminActionForTargetedMedia); + } else { + removeAdminActionComponent.removeAdminActionFromAllVersions(targetedMedia); + return GetAdminMediaResponseMapper.mapHideOrShowResponse(targetedMedia, null); + } + } + @Override public List getMediasMarkedForDeletion() { if (!this.isManualDeletionEnabled()) { @@ -226,4 +264,14 @@ public MediaApproveMarkedForDeletionResponse adminApproveMediaMarkedForDeletion( return GetAdminMediaResponseMapper.mapMediaApproveMarkedForDeletionResponse(mediaEntity, objectAdminActionEntity); } + + private ApplyAdminActionComponent.AdminActionProperties mapToAdminActionProperties(AdminActionRequest adminActionRequest) { + final ObjectHiddenReasonEntity objectHiddenReason = hiddenReasonRepository.findById(adminActionRequest.getReasonId()) + .orElseThrow(() -> new DartsApiException(AudioApiError.MEDIA_HIDE_ACTION_REASON_NOT_FOUND)); + + return new ApplyAdminActionComponent.AdminActionProperties(adminActionRequest.getTicketReference(), + adminActionRequest.getComments(), + objectHiddenReason); + } + } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImpl.java index b97f71ed1b..bc5612d588 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImpl.java @@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import uk.gov.hmcts.darts.audio.component.AddAudioRequestMapper; +import uk.gov.hmcts.darts.audio.component.impl.ApplyAdminActionComponent; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.model.AddAudioMetadataRequest; import uk.gov.hmcts.darts.audio.service.AudioAsyncService; @@ -34,6 +35,7 @@ import java.time.Duration; import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -56,6 +58,7 @@ public class AudioUploadServiceImpl implements AudioUploadService { private final UserIdentity userIdentity; private final LogApi logApi; private final AudioAsyncService audioAsyncService; + private final ApplyAdminActionComponent applyAdminActionComponent; @Value("${darts.audio.small-file-max-length}") private Duration smallFileSizeMaxLength; @@ -128,7 +131,8 @@ public void addAudio(String blodId, AddAudioMetadataRequest addAudioMetadataRequ void versionUpload(List mediaToSupersede, AddAudioMetadataRequest addAudioMetadataRequest, - String externalLocation, String checksum, + String externalLocation, + String checksum, UserAccountEntity userAccount) { MediaEntity newMediaEntity = mapper.mapToMedia(addAudioMetadataRequest, userAccount); @@ -144,6 +148,9 @@ void versionUpload(List mediaToSupersede, newMediaEntity.setAntecedentId(String.valueOf(oldMediaEntity.getId())); log.info("Revised version of media added with filename {} and antecedent media id {}", newMediaEntity.getMediaFile(), newMediaEntity.getId().toString()); + if (oldMediaEntity.isHidden()) { + copyAdminActionToNewMedia(oldMediaEntity, newMediaEntity); + } } newMediaEntity = mediaRepository.saveAndFlush(newMediaEntity); log.info("Saved media id {}", newMediaEntity.getId()); @@ -250,4 +257,18 @@ void saveExternalObjectDirectory(String externalLocation, externalObjectDirectoryRepository.save(externalObjectDirectoryEntity); } + private void copyAdminActionToNewMedia(MediaEntity oldMediaEntity, MediaEntity newMediaEntity) { + ApplyAdminActionComponent.AdminActionProperties adminActionProperties = oldMediaEntity.getObjectAdminAction() + .map(adminActionEntity -> + new ApplyAdminActionComponent.AdminActionProperties(adminActionEntity.getTicketReference(), + adminActionEntity.getComments(), + adminActionEntity.getObjectHiddenReason())) + .orElseGet(() -> + new ApplyAdminActionComponent.AdminActionProperties(null, + "Prior version had no admin action, so no details are available", + null)); + + applyAdminActionComponent.applyAdminActionTo(Collections.singletonList(newMediaEntity), adminActionProperties); + } + } diff --git a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImpl.java index 9098442a48..1158055c73 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImpl.java @@ -18,17 +18,13 @@ import uk.gov.hmcts.darts.audio.enums.MediaRequestStatus; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.exception.AudioRequestsApiError; -import uk.gov.hmcts.darts.audio.mapper.GetAdminMediaResponseMapper; import uk.gov.hmcts.darts.audio.mapper.GetTransformedMediaDetailsMapper; import uk.gov.hmcts.darts.audio.mapper.MediaRequestDetailsMapper; import uk.gov.hmcts.darts.audio.mapper.TransformedMediaMapper; import uk.gov.hmcts.darts.audio.model.EnhancedMediaRequestInfo; -import uk.gov.hmcts.darts.audio.model.MediaHideRequest; -import uk.gov.hmcts.darts.audio.model.MediaHideResponse; import uk.gov.hmcts.darts.audio.model.TransformedMediaDetailsDto; import uk.gov.hmcts.darts.audio.service.MediaRequestService; import uk.gov.hmcts.darts.audio.validation.AudioMediaPatchRequestValidator; -import uk.gov.hmcts.darts.audio.validation.MediaHideOrShowValidator; import uk.gov.hmcts.darts.audiorequests.model.AudioNonAccessedResponse; import uk.gov.hmcts.darts.audiorequests.model.AudioRequestDetails; import uk.gov.hmcts.darts.audiorequests.model.AudioRequestType; @@ -50,9 +46,6 @@ import uk.gov.hmcts.darts.common.entity.CourthouseEntity_; import uk.gov.hmcts.darts.common.entity.HearingEntity; import uk.gov.hmcts.darts.common.entity.HearingEntity_; -import uk.gov.hmcts.darts.common.entity.MediaEntity; -import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; -import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; import uk.gov.hmcts.darts.common.entity.TransformedMediaEntity; import uk.gov.hmcts.darts.common.entity.TransientObjectDirectoryEntity; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; @@ -61,10 +54,7 @@ import uk.gov.hmcts.darts.common.exception.DartsException; import uk.gov.hmcts.darts.common.helper.CurrentTimeHelper; import uk.gov.hmcts.darts.common.helper.SystemUserHelper; -import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.repository.MediaRequestRepository; -import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; -import uk.gov.hmcts.darts.common.repository.ObjectHiddenReasonRepository; import uk.gov.hmcts.darts.common.repository.TransformedMediaRepository; import uk.gov.hmcts.darts.common.repository.TransientObjectDirectoryRepository; import uk.gov.hmcts.darts.common.repository.UserAccountRepository; @@ -91,7 +81,6 @@ import static uk.gov.hmcts.darts.audit.api.AuditActivity.AUDIO_PLAYBACK; import static uk.gov.hmcts.darts.audit.api.AuditActivity.CHANGE_AUDIO_OWNERSHIP; import static uk.gov.hmcts.darts.audit.api.AuditActivity.EXPORT_AUDIO; -import static uk.gov.hmcts.darts.audit.api.AuditActivity.HIDE_AUDIO; import static uk.gov.hmcts.darts.audit.api.AuditActivity.REQUEST_AUDIO; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.STORED; import static uk.gov.hmcts.darts.notification.api.NotificationApi.NotificationTemplate.AUDIO_REQUEST_PROCESSING; @@ -120,10 +109,6 @@ public class MediaRequestServiceImpl implements MediaRequestService { private final GetTransformedMediaDetailsMapper getTransformedMediaDetailsMapper; private final MediaRequestMapper mediaRequestMapper; private final AudioMediaPatchRequestValidator mediaRequestValidator; - private final MediaRepository mediaRepository; - private final MediaHideOrShowValidator mediaHideOrShowValidator; - private final ObjectAdminActionRepository objectAdminActionRepository; - private final ObjectHiddenReasonRepository objectHiddenReasonRepository; private final SystemUserHelper systemUserHelper; @Override @@ -521,64 +506,4 @@ private void auditOwnerChange(MediaPatchRequest request, MediaRequestEntity medi } } - @Override - @Transactional - public MediaHideResponse adminHideOrShowMediaById(Integer mediaId, MediaHideRequest mediaHideRequest) { - MediaHideResponse response; - - IdRequest request = new IdRequest<>(mediaHideRequest, mediaId); - mediaHideOrShowValidator.validate(request); - - Optional mediaEntityOptional - = mediaRepository.findByIdIncludeDeleted(mediaId); - if (mediaEntityOptional.isPresent()) { - MediaEntity mediaEntity = mediaEntityOptional.get(); - - mediaEntity.setHidden(mediaHideRequest.getIsHidden()); - mediaRepository.saveAndFlush(mediaEntity); - - if (request.getPayload().getIsHidden()) { - Optional objectHiddenReasonEntity - = objectHiddenReasonRepository.findById(mediaHideRequest.getAdminAction().getReasonId()); - - if (objectHiddenReasonEntity.isEmpty()) { - throw new DartsApiException(AudioApiError.MEDIA_HIDE_ACTION_REASON_NOT_FOUND); - } - - auditApi.record(HIDE_AUDIO); - - // on hiding add the relevant hide record - ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); - objectAdminActionEntity.setObjectHiddenReason(objectHiddenReasonEntity.get()); - objectAdminActionEntity.setTicketReference(mediaHideRequest.getAdminAction().getTicketReference()); - objectAdminActionEntity.setComments(mediaHideRequest.getAdminAction().getComments()); - objectAdminActionEntity.setMedia(mediaEntity); - objectAdminActionEntity.setHiddenBy(userIdentity.getUserAccount()); - objectAdminActionEntity.setHiddenDateTime(currentTimeHelper.currentOffsetDateTime()); - objectAdminActionEntity.setMarkedForManualDeletion(false); - - objectAdminActionEntity = objectAdminActionRepository.saveAndFlush(objectAdminActionEntity); - - response = GetAdminMediaResponseMapper.mapHideOrShowResponse(mediaEntity, objectAdminActionEntity); - } else { - List objectAdminActionEntityLst = objectAdminActionRepository.findByMedia_Id(mediaId); - - response = GetAdminMediaResponseMapper.mapHideOrShowResponse(mediaEntityOptional.get(), null); - - for (ObjectAdminActionEntity objectAdminActionEntity : objectAdminActionEntityLst) { - auditApi.record(AuditActivity.UNHIDE_AUDIO, buildUnhideAudioAdditionalDataString(objectAdminActionEntity)); - objectAdminActionRepository.deleteById(objectAdminActionEntity.getId()); - } - } - } else { - throw new DartsApiException(AudioApiError.MEDIA_NOT_FOUND); - } - - return response; - } - - private String buildUnhideAudioAdditionalDataString(ObjectAdminActionEntity objectAdminActionEntity) { - return "Ticket reference: " + objectAdminActionEntity.getTicketReference() + ", Comments: " + objectAdminActionEntity.getComments(); - } - } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/casedocument/mapper/CaseObjectsCaseDocumentMapper.java b/src/main/java/uk/gov/hmcts/darts/casedocument/mapper/CaseObjectsCaseDocumentMapper.java index e870c15e53..5bea1d96cb 100644 --- a/src/main/java/uk/gov/hmcts/darts/casedocument/mapper/CaseObjectsCaseDocumentMapper.java +++ b/src/main/java/uk/gov/hmcts/darts/casedocument/mapper/CaseObjectsCaseDocumentMapper.java @@ -27,6 +27,7 @@ public abstract class CaseObjectsCaseDocumentMapper { @Mappings({ @Mapping(expression = "java(mapEods(eodRepository.findByMedia(mediaEntity)))", target = "externalObjectDirectories"), + @Mapping(source = "objectAdminActions", target = "adminActionReasons"), }) public abstract MediaCaseDocument map(MediaEntity mediaEntity); diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/MediaEntity.java b/src/main/java/uk/gov/hmcts/darts/common/entity/MediaEntity.java index 9d1f0b21ee..8d3352c7ed 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/entity/MediaEntity.java +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/MediaEntity.java @@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.SQLRestriction; import uk.gov.hmcts.darts.common.entity.base.CreatedModifiedBaseEntity; import uk.gov.hmcts.darts.retention.enums.RetentionConfidenceScoreEnum; @@ -27,7 +28,9 @@ import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +@Slf4j @Entity @Table(name = "media") @Getter @@ -123,7 +126,7 @@ public class MediaEntity extends CreatedModifiedBaseEntity @OneToMany(mappedBy = ObjectAdminActionEntity_.MEDIA, fetch = FetchType.LAZY) - private List adminActionReasons = new ArrayList<>(); + private List objectAdminActions = new ArrayList<>(); @Column(name = "ret_conf_score") private RetentionConfidenceScoreEnum retConfScore; @@ -165,4 +168,17 @@ public void setDeletedTs(OffsetDateTime deletedTs) { public OffsetDateTime getDeletedTs() { return getDeletedTimestamp(); } + + public Optional getObjectAdminAction() { + if (objectAdminActions.size() > 1) { + log.warn("Media id {} has more than one admin action, yet the application logic expects Media->ObjectAdminAction is 1:1", id); + } + return objectAdminActions.stream().findFirst(); + } + + public void setObjectAdminAction(ObjectAdminActionEntity adminAction) { + objectAdminActions.clear(); + objectAdminActions.add(adminAction); + } + } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/common/repository/MediaRepository.java b/src/main/java/uk/gov/hmcts/darts/common/repository/MediaRepository.java index 458dcd482c..2fe2467f40 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/repository/MediaRepository.java +++ b/src/main/java/uk/gov/hmcts/darts/common/repository/MediaRepository.java @@ -113,4 +113,7 @@ SELECT COUNT(me) WHERE me.chronicleId = :chronicleId """) Integer getVersionCount(String chronicleId); + + List findAllByChronicleId(String chronicleId); + } \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponentTest.java b/src/test/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponentTest.java new file mode 100644 index 0000000000..abf0dbab7f --- /dev/null +++ b/src/test/java/uk/gov/hmcts/darts/audio/component/impl/ApplyAdminActionComponentTest.java @@ -0,0 +1,280 @@ +package uk.gov.hmcts.darts.audio.component.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.darts.audit.api.AuditActivity; +import uk.gov.hmcts.darts.audit.api.AuditApi; +import uk.gov.hmcts.darts.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.helper.CurrentTimeHelper; +import uk.gov.hmcts.darts.common.repository.MediaRepository; +import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ApplyAdminActionComponentTest { + + @Mock + private UserIdentity userIdentity; + @Mock + private CurrentTimeHelper currentTimeHelper; + @Mock + private RemoveAdminActionComponent removeAdminActionComponent; + + @Mock + private MediaRepository mediaRepository; + @Mock + private ObjectAdminActionRepository adminActionRepository; + + @Mock + private AuditApi auditApi; + + private ApplyAdminActionComponent applyAdminActionComponent; + + private ObjectHiddenReasonEntity objectHiddenReasonEntity; + private UserAccountEntity userAccountEntity; + private OffsetDateTime someDateTime; + + @BeforeEach + void setUp() { + applyAdminActionComponent = new ApplyAdminActionComponent(userIdentity, + currentTimeHelper, + removeAdminActionComponent, + mediaRepository, + adminActionRepository, + auditApi); + } + + @Nested + class ApplyAdminActionToAllVersionsTests { + + + + @BeforeEach + void setUp() { + objectHiddenReasonEntity = new ObjectHiddenReasonEntity(); + + userAccountEntity = PersistableFactory.getUserAccountTestData().someMinimal(); + when(userIdentity.getUserAccount()) + .thenReturn(userAccountEntity); + + someDateTime = OffsetDateTime.parse("2025-01-01T00:00:00Z"); + when(currentTimeHelper.currentOffsetDateTime()) + .thenReturn(someDateTime); + } + + @Test + void shouldHideAndSetAdminActionOnTargetedMedia_whenTargetedMediaHasNoChronicleId() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .build() + .getEntity(); + + var adminActionProperty = new ApplyAdminActionComponent.AdminActionProperties("Some ticket reference", + "Some comments", + objectHiddenReasonEntity); + + // When + List mediaEntities = applyAdminActionComponent.applyAdminActionToAllVersions(targetedMedia, adminActionProperty); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity updatedMedia = mediaEntities.getFirst(); + + assertTrue(updatedMedia.isHidden()); + + Optional adminActionOptional = updatedMedia.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + + assertEquals("Some ticket reference", adminAction.getTicketReference()); + assertEquals("Some comments", adminAction.getComments()); + assertEquals(targetedMedia.getId(), adminAction.getMedia().getId()); + assertEquals(objectHiddenReasonEntity, adminAction.getObjectHiddenReason()); + assertEquals(userAccountEntity, adminAction.getHiddenBy()); + assertEquals(someDateTime, adminAction.getHiddenDateTime()); + assertFalse(adminAction.isMarkedForManualDeletion()); + + verify(removeAdminActionComponent).removeAdminActionFrom(List.of(targetedMedia)); + verifyNoMoreInteractions(removeAdminActionComponent); + + verify(adminActionRepository).saveAndFlush(adminAction); + verifyNoMoreInteractions(adminActionRepository); + + verify(mediaRepository).saveAndFlush(updatedMedia); + verifyNoMoreInteractions(mediaRepository); + + verify(auditApi).record(AuditActivity.HIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference"); + verifyNoMoreInteractions(auditApi); + } + + @Test + void shouldHideAndSetAdminActionForAllVersions_whenTargetedMediaHasOtherVersions() { + // Given + final String commonChronicleId = "1000"; + + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId(commonChronicleId) + .build() + .getEntity(); + MediaEntity otherVersion = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(2) + .chronicleId(commonChronicleId) + .build() + .getEntity(); + when(mediaRepository.findAllByChronicleId(commonChronicleId)) + .thenReturn(List.of(targetedMedia, otherVersion)); + + var adminActionProperty = new ApplyAdminActionComponent.AdminActionProperties("Some ticket reference", + "Some comments", + objectHiddenReasonEntity); + + // When + List mediaEntities = applyAdminActionComponent.applyAdminActionToAllVersions(targetedMedia, adminActionProperty); + + // Then + assertEquals(2, mediaEntities.size()); + + // Assert what we expect to be common across all versions + for (MediaEntity updatedMedia : mediaEntities) { + assertTrue(updatedMedia.isHidden()); + + Optional adminActionOptional = updatedMedia.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + + assertEquals("Some ticket reference", adminAction.getTicketReference()); + assertEquals("Some comments", adminAction.getComments()); + assertEquals(objectHiddenReasonEntity, adminAction.getObjectHiddenReason()); + assertEquals(userAccountEntity, adminAction.getHiddenBy()); + assertEquals(someDateTime, adminAction.getHiddenDateTime()); + assertFalse(adminAction.isMarkedForManualDeletion()); + + verify(adminActionRepository).saveAndFlush(adminAction); + verify(mediaRepository).saveAndFlush(updatedMedia); + } + verifyNoMoreInteractions(adminActionRepository); + verifyNoMoreInteractions(mediaRepository); + + verify(removeAdminActionComponent).removeAdminActionFrom(List.of(targetedMedia, otherVersion)); + verifyNoMoreInteractions(removeAdminActionComponent); + + verify(auditApi).record(AuditActivity.HIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference"); + verify(auditApi).record(AuditActivity.HIDE_AUDIO, "Media id: 2, Ticket ref: Some ticket reference"); + verifyNoMoreInteractions(auditApi); + + // And verify the back-links + List backLinkedMediaIds = mediaEntities.stream() + .map(MediaEntity::getObjectAdminActions) + .flatMap(List::stream) + .map(ObjectAdminActionEntity::getMedia) + .map(MediaEntity::getId) + .toList(); + assertThat(backLinkedMediaIds, containsInAnyOrder(targetedMedia.getId(), otherVersion.getId())); + } + } + + @Nested + class ApplyAdminActionToTests { + + @BeforeEach + void setUp() { + objectHiddenReasonEntity = new ObjectHiddenReasonEntity(); + + userAccountEntity = PersistableFactory.getUserAccountTestData().someMinimal(); + when(userIdentity.getUserAccount()) + .thenReturn(userAccountEntity); + + someDateTime = OffsetDateTime.parse("2025-01-01T00:00:00Z"); + when(currentTimeHelper.currentOffsetDateTime()) + .thenReturn(someDateTime); + } + + @Test + void shouldHideAndSetAdminActionForAllProvidedMedias() { + // Given + final String commonChronicleId = "1000"; + + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId(commonChronicleId) + .build() + .getEntity(); + MediaEntity otherVersion = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(2) + .chronicleId(commonChronicleId) + .build() + .getEntity(); + + var adminActionProperty = new ApplyAdminActionComponent.AdminActionProperties("Some ticket reference", + "Some comments", + objectHiddenReasonEntity); + + // When + List mediaEntities = applyAdminActionComponent.applyAdminActionTo(List.of(targetedMedia, otherVersion), + adminActionProperty); + // Then + assertEquals(2, mediaEntities.size()); + + // Assert what we expect to be common across all versions + for (MediaEntity updatedMedia : mediaEntities) { + assertTrue(updatedMedia.isHidden()); + + Optional adminActionOptional = updatedMedia.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + ObjectAdminActionEntity adminAction = adminActionOptional.get(); + + assertEquals("Some ticket reference", adminAction.getTicketReference()); + assertEquals("Some comments", adminAction.getComments()); + assertEquals(objectHiddenReasonEntity, adminAction.getObjectHiddenReason()); + assertEquals(userAccountEntity, adminAction.getHiddenBy()); + assertEquals(someDateTime, adminAction.getHiddenDateTime()); + assertFalse(adminAction.isMarkedForManualDeletion()); + + verify(adminActionRepository).saveAndFlush(adminAction); + verify(mediaRepository).saveAndFlush(updatedMedia); + } + verifyNoMoreInteractions(adminActionRepository); + verifyNoMoreInteractions(mediaRepository); + + verify(removeAdminActionComponent).removeAdminActionFrom(List.of(targetedMedia, otherVersion)); + verifyNoMoreInteractions(removeAdminActionComponent); + + verify(auditApi).record(AuditActivity.HIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference"); + verify(auditApi).record(AuditActivity.HIDE_AUDIO, "Media id: 2, Ticket ref: Some ticket reference"); + verifyNoMoreInteractions(auditApi); + + // And verify the back-links + List backLinkedMediaIds = mediaEntities.stream() + .map(MediaEntity::getObjectAdminActions) + .flatMap(List::stream) + .map(ObjectAdminActionEntity::getMedia) + .map(MediaEntity::getId) + .toList(); + assertThat(backLinkedMediaIds, containsInAnyOrder(targetedMedia.getId(), otherVersion.getId())); + } + } + +} diff --git a/src/test/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponentTest.java b/src/test/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponentTest.java new file mode 100644 index 0000000000..cd66349aa8 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/darts/audio/component/impl/RemoveAdminActionComponentTest.java @@ -0,0 +1,309 @@ +package uk.gov.hmcts.darts.audio.component.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.darts.audit.api.AuditActivity; +import uk.gov.hmcts.darts.audit.api.AuditApi; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.repository.MediaRepository; +import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; +import uk.gov.hmcts.darts.test.common.data.MediaTestData; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; + +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RemoveAdminActionComponentTest { + + @Mock + private MediaRepository mediaRepository; + @Mock + private ObjectAdminActionRepository adminActionRepository; + + @Mock + private AuditApi auditApi; + + private RemoveAdminActionComponent removeAdminActionComponent; + + @BeforeEach + void setUp() { + removeAdminActionComponent = new RemoveAdminActionComponent(mediaRepository, + adminActionRepository, + auditApi); + } + + @Nested + class RemoveAdminActionFromAllVersionsTests { + + @Test + void shouldUnHideTargetedMediaAndRemoveAdminAction_whenTargetedMediaIsHiddenAndHasNoChronicleId() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId(null) + .isHidden(true) + .build() + .getEntity(); + + ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); + objectAdminActionEntity.setId(100); + objectAdminActionEntity.setTicketReference("Some ticket reference"); + objectAdminActionEntity.setComments("Some comments"); + targetedMedia.setObjectAdminAction(objectAdminActionEntity); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFromAllVersions(targetedMedia); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + + verify(adminActionRepository).deleteById(eq(100)); + verifyNoMoreInteractions(adminActionRepository); + + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference, Comments: Some comments"); + verifyNoMoreInteractions(auditApi); + + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(1))); + verifyNoMoreInteractions(mediaRepository); + } + + @Test + void shouldUnHideAndSetAdminActionForAllVersions_whenTargetedMediaIsHiddenAndHasOtherVersions() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId("1000") + .isHidden(true) + .build() + .getEntity(); + + ObjectAdminActionEntity adminActionForTargetedMedia = new ObjectAdminActionEntity(); + adminActionForTargetedMedia.setId(100); + adminActionForTargetedMedia.setTicketReference("Some ticket reference"); + adminActionForTargetedMedia.setComments("Some comments"); + targetedMedia.setObjectAdminAction(adminActionForTargetedMedia); + + MediaEntity otherVersion = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(2) + .chronicleId("1000") + .isHidden(true) + .build() + .getEntity(); + + ObjectAdminActionEntity adminActionForOtherVersion = new ObjectAdminActionEntity(); + adminActionForOtherVersion.setId(200); + adminActionForOtherVersion.setTicketReference("Some ticket reference"); + adminActionForOtherVersion.setComments("Some comments"); + otherVersion.setObjectAdminAction(adminActionForOtherVersion); + + when(mediaRepository.findAllByChronicleId("1000")).thenReturn(List.of(targetedMedia, otherVersion)); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFromAllVersions(targetedMedia); + + // Then + assertEquals(2, mediaEntities.size()); + { + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + } + { + MediaEntity mediaEntity = mediaEntities.get(1); + assertEquals(2, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + } + + verify(adminActionRepository).deleteById(eq(100)); + verify(adminActionRepository).deleteById(eq(200)); + verifyNoMoreInteractions(adminActionRepository); + + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference, Comments: Some comments"); + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 2, Ticket ref: Some ticket reference, Comments: Some comments"); + verifyNoMoreInteractions(auditApi); + + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(1))); + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(2))); + verifyNoMoreInteractions(mediaRepository); + } + + } + + @Nested + class RemoveAdminActionFromTests { + + @Test + void shouldUnHideTargetedMediaAndRemoveAdminAction_whenTargetedMediaIsHiddenAndHasExistingAdminActionAndHasNoChronicleId() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId(null) + .isHidden(true) + .build() + .getEntity(); + + ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); + objectAdminActionEntity.setId(100); + objectAdminActionEntity.setTicketReference("Some ticket reference"); + objectAdminActionEntity.setComments("Some comments"); + targetedMedia.setObjectAdminAction(objectAdminActionEntity); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFrom(Collections.singletonList(targetedMedia)); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + + verify(adminActionRepository).deleteById(eq(100)); + verifyNoMoreInteractions(adminActionRepository); + + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference, Comments: Some comments"); + verifyNoMoreInteractions(auditApi); + + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(1))); + verifyNoMoreInteractions(mediaRepository); + } + + @Test + void shouldUnHideTargetedMedia_whenTargetedMediaIsHiddenAndHasNoExistingAdminAction() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId("1000") + .isHidden(true) + .build() + .getEntity(); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFrom(Collections.singletonList(targetedMedia)); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + + verifyNoInteractions(adminActionRepository); + + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 1, Ticket ref: null, Comments: null"); + verifyNoMoreInteractions(auditApi); + + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(1))); + verifyNoMoreInteractions(mediaRepository); + } + + @Test + void shouldUnHideTargetedMedia_whenTargetedMediaIsNotHiddenAndHasExistingAdminAction() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId("1000") + .isHidden(false) + .build() + .getEntity(); + + ObjectAdminActionEntity adminActionForTargetedMedia = new ObjectAdminActionEntity(); + adminActionForTargetedMedia.setId(100); + adminActionForTargetedMedia.setTicketReference("Some ticket reference"); + adminActionForTargetedMedia.setComments("Some comments"); + targetedMedia.setObjectAdminAction(adminActionForTargetedMedia); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFrom(Collections.singletonList(targetedMedia)); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + + verify(adminActionRepository).deleteById(eq(100)); + verifyNoMoreInteractions(adminActionRepository); + + verify(auditApi).record(AuditActivity.UNHIDE_AUDIO, "Media id: 1, Ticket ref: Some ticket reference, Comments: Some comments"); + verifyNoMoreInteractions(auditApi); + + verify(mediaRepository).saveAndFlush(argThat(media -> media.getId().equals(1))); + verifyNoMoreInteractions(mediaRepository); + } + + @Test + void shouldNotUnHideTargetedMedia_whenTargetedMediaIsNotHiddenAndHasNoExistingAdminAction() { + // Given + MediaEntity targetedMedia = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .chronicleId("1000") + .isHidden(false) + .build() + .getEntity(); + + // When + List mediaEntities = removeAdminActionComponent.removeAdminActionFrom(Collections.singletonList(targetedMedia)); + + // Then + assertEquals(1, mediaEntities.size()); + MediaEntity mediaEntity = mediaEntities.getFirst(); + assertEquals(1, mediaEntity.getId()); + assertFalse(mediaEntity.isHidden()); + assertFalse(mediaEntity.getObjectAdminAction().isPresent()); + + verifyNoInteractions(adminActionRepository); + verifyNoInteractions(auditApi); + verifyNoInteractions(mediaRepository); + } + + @Test + void shouldThrowException_whenMediasHaveDifferingChronicleIds() { + // Given + MediaTestData mediaTestData = PersistableFactory.getMediaTestData(); + + MediaEntity media1 = mediaTestData.someMinimalBuilder() + .id(1) + .chronicleId("1000") + .build() + .getEntity(); + MediaEntity media2 = mediaTestData.someMinimalBuilder() + .id(2) + .chronicleId("2000") + .build() + .getEntity(); + + // When + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> removeAdminActionComponent.removeAdminActionFrom(List.of(media1, media2))); + + // Then + assertEquals("All media versions must have the same chronicle id", exception.getMessage()); + } + + } + +} \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java index 7e75259e30..e2211c1319 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AdminMediaServiceImplTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -10,11 +11,15 @@ import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.test.util.ReflectionTestUtils; +import uk.gov.hmcts.darts.audio.component.impl.ApplyAdminActionComponent; +import uk.gov.hmcts.darts.audio.component.impl.RemoveAdminActionComponent; import uk.gov.hmcts.darts.audio.entity.MediaRequestEntity; import uk.gov.hmcts.darts.audio.mapper.AdminMarkedForDeletionMapper; import uk.gov.hmcts.darts.audio.mapper.AdminMarkedForDeletionMapperImpl; @@ -22,15 +27,19 @@ import uk.gov.hmcts.darts.audio.mapper.CourthouseMapperImpl; import uk.gov.hmcts.darts.audio.mapper.CourtroomMapper; import uk.gov.hmcts.darts.audio.mapper.CourtroomMapperImpl; +import uk.gov.hmcts.darts.audio.mapper.GetAdminMediaResponseMapper; import uk.gov.hmcts.darts.audio.mapper.ObjectActionMapper; import uk.gov.hmcts.darts.audio.mapper.ObjectActionMapperImpl; +import uk.gov.hmcts.darts.audio.model.AdminActionRequest; import uk.gov.hmcts.darts.audio.model.AdminMediaCourthouseResponse; import uk.gov.hmcts.darts.audio.model.AdminMediaCourtroomResponse; import uk.gov.hmcts.darts.audio.model.GetAdminMediaResponseItem; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionAdminAction; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionItem; import uk.gov.hmcts.darts.audio.model.GetAdminMediasMarkedForDeletionMediaItem; +import uk.gov.hmcts.darts.audio.model.MediaHideRequest; import uk.gov.hmcts.darts.audio.model.MediaSearchData; +import uk.gov.hmcts.darts.audio.validation.MediaHideOrShowValidator; import uk.gov.hmcts.darts.audio.validation.SearchMediaValidator; import uk.gov.hmcts.darts.common.entity.CourtCaseEntity; import uk.gov.hmcts.darts.common.entity.CourthouseEntity; @@ -45,13 +54,16 @@ import uk.gov.hmcts.darts.common.exception.DartsApiException; import uk.gov.hmcts.darts.common.repository.MediaRepository; import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; +import uk.gov.hmcts.darts.common.repository.ObjectHiddenReasonRepository; import uk.gov.hmcts.darts.common.repository.TransformedMediaRepository; import uk.gov.hmcts.darts.test.common.TestUtils; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -59,12 +71,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +@SuppressWarnings("PMD.CouplingBetweenObjects") @ExtendWith(MockitoExtension.class) class AdminMediaServiceImplTest { @InjectMocks @@ -79,6 +94,14 @@ class AdminMediaServiceImplTest { private TransformedMediaRepository mockTransformedMediaRepository; @Mock private SearchMediaValidator searchMediaValidator; + @Mock + private MediaHideOrShowValidator mediaHideOrShowValidator; + @Mock + private ApplyAdminActionComponent applyAdminActionComponent; + @Mock + private RemoveAdminActionComponent removeAdminActionComponent; + @Mock + private ObjectHiddenReasonRepository hiddenReasonRepository; private ObjectMapper objectMapper; @@ -699,4 +722,118 @@ private void assertCourthouse(AdminMediaCourthouseResponse actual, String expect } } + @Nested + class AdminHideOrShowMediaByIdTests { + + private MediaEntity mediaEntity; + + private MockedStatic mediaResponseMapperMockedStatic; + + @BeforeEach + void setUp() { + mediaResponseMapperMockedStatic = Mockito.mockStatic(GetAdminMediaResponseMapper.class); + + mediaEntity = PersistableFactory.getMediaTestData().someMinimalBuilder() + .id(1) + .build() + .getEntity(); + when(mediaRepository.findByIdIncludeDeleted(1)) + .thenReturn(Optional.of(mediaEntity)); + } + + @AfterEach + void tearDown() { + if (mediaResponseMapperMockedStatic != null) { + mediaResponseMapperMockedStatic.close(); + } + } + + @Test + void shouldInvokeHideFunctionality_whenMediaHideRequestHasIsHiddenTrue() { + // Given + ObjectHiddenReasonEntity objectHiddenReasonEntity = new ObjectHiddenReasonEntity(); + when(hiddenReasonRepository.findById(0)) + .thenReturn(Optional.of(objectHiddenReasonEntity)); + + ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); + when(objectAdminActionRepository.findByMedia_Id(1)) + .thenReturn(Collections.singletonList(objectAdminActionEntity)); + + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + mediaHideRequest.setIsHidden(true); + + AdminActionRequest adminActionRequest = new AdminActionRequest(); + adminActionRequest.setReasonId(0); + adminActionRequest.setTicketReference("Some reference"); + adminActionRequest.setComments("Some comments"); + + mediaHideRequest.setAdminAction(adminActionRequest); + + // When + mediaRequestService.adminHideOrShowMediaById(1, mediaHideRequest); + + // Then + var expectedActionProperties = new ApplyAdminActionComponent.AdminActionProperties("Some reference", + "Some comments", + objectHiddenReasonEntity); + verify(applyAdminActionComponent).applyAdminActionToAllVersions(eq(mediaEntity), eq(expectedActionProperties)); + } + + @Test + void shouldThrowException_whenProvidedHiddenReasonDoesNotExist() { + // Given + when(hiddenReasonRepository.findById(0)) + .thenReturn(Optional.empty()); + + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + mediaHideRequest.setIsHidden(true); + + AdminActionRequest adminActionRequest = new AdminActionRequest(); + adminActionRequest.setReasonId(0); + adminActionRequest.setTicketReference("Some reference"); + adminActionRequest.setComments("Some comments"); + + mediaHideRequest.setAdminAction(adminActionRequest); + + // When + DartsApiException exception = assertThrows(DartsApiException.class, () -> + mediaRequestService.adminHideOrShowMediaById(1, mediaHideRequest)); + + // Then + assertEquals("Hide reason is incorrect", exception.getMessage()); + verifyNoInteractions(objectAdminActionRepository); + verifyNoInteractions(applyAdminActionComponent); + } + + @Test + void shouldInvokeUnhideFunctionality_whenMediaHideRequestHasIsHiddenFalse() { + // Given + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + mediaHideRequest.setIsHidden(false); + + // When + mediaRequestService.adminHideOrShowMediaById(1, mediaHideRequest); + + // Then + verify(removeAdminActionComponent).removeAdminActionFromAllVersions(eq(mediaEntity)); + } + + @Test + void shouldThrowException_whenNoMediaIsFound() { + // Given + when(mediaRepository.findByIdIncludeDeleted(1)) + .thenReturn(Optional.empty()); + + MediaHideRequest mediaHideRequest = new MediaHideRequest(); + + // When + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> mediaRequestService.adminHideOrShowMediaById(1, mediaHideRequest)); + + // Then + assertEquals(exception.getMessage(), "Media not found, expected this to be pre-validated"); + } + + } + } \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImplTest.java index 1b3c29e8b5..b3af348518 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioUploadServiceImplTest.java @@ -12,6 +12,7 @@ import org.springframework.test.util.ReflectionTestUtils; import uk.gov.hmcts.darts.audio.component.AddAudioRequestMapper; import uk.gov.hmcts.darts.audio.component.impl.AddAudioRequestMapperImpl; +import uk.gov.hmcts.darts.audio.component.impl.ApplyAdminActionComponent; import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.model.AddAudioMetadataRequest; import uk.gov.hmcts.darts.audio.service.AudioAsyncService; @@ -22,6 +23,8 @@ import uk.gov.hmcts.darts.common.entity.ExternalObjectDirectoryEntity; import uk.gov.hmcts.darts.common.entity.HearingEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.common.exception.AzureDeleteBlobException; import uk.gov.hmcts.darts.common.exception.DartsApiException; @@ -45,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -90,6 +94,8 @@ class AudioUploadServiceImplTest { private AudioAsyncService audioAsyncService; @Mock private MediaLinkedCaseHelper mediaLinkedCaseHelper; + @Mock + private ApplyAdminActionComponent applyAdminActionComponent; private AddAudioRequestMapper mapper; @BeforeEach @@ -105,7 +111,9 @@ void setUp() { dataManagementApi, userIdentity, logApi, - audioAsyncService)); + audioAsyncService, + applyAdminActionComponent + )); ReflectionTestUtils.setField(audioService, "smallFileSizeMaxLength", Duration.ofSeconds(2)); ReflectionTestUtils.setField(audioService, "smallFileSize", 1024); @@ -253,6 +261,133 @@ void versionUpload_shouldLogSmallFileWithLongDurationWarning_whenFileIs1025Bytes verify(logApi, never()).addAudioSmallFileWithLongDuration(any(), any(), any(), any(), any(), any()); } + @Test + void versionUpload_shouldNotInvokeHideAllFunctionalityIfExistingMediaIsNotHidden() { + MediaEntity exisingMediaVersion = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(100) + .chronicleId("100") + .antecedentId(null) + .build() + .getEntity(); + + MediaEntity newMedia = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(101) + .chronicleId("100") + .antecedentId("100") + .build() + .getEntity(); + doReturn(newMedia).when(mapper).mapToMedia(any(), any()); + + AddAudioMetadataRequest addAudioMetadataRequest = new AddAudioMetadataRequest(); + addAudioMetadataRequest.setStartedAt(STARTED_AT); + addAudioMetadataRequest.setEndedAt(ENDED_AT); + addAudioMetadataRequest.setFileSize(100L); + addAudioMetadataRequest.setCases(Collections.emptyList()); + + audioService.versionUpload(List.of(exisingMediaVersion), + addAudioMetadataRequest, + UUID.randomUUID().toString(), + "checksum", + PersistableFactory.getUserAccountTestData().someMinimal()); + + verifyNoInteractions(applyAdminActionComponent); + } + + @Test + void versionUpload_shouldInvokeHideAllFunctionalityWithLimitedAdminActionDetailsIfExistingMediaIsHiddenWithNoExistingAdminAction() { + MediaEntity exisingMediaVersion = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(100) + .isHidden(true) + .chronicleId("100") + .antecedentId(null) + .build() + .getEntity(); + + MediaEntity newMedia = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(101) + .chronicleId("100") + .antecedentId("100") + .build() + .getEntity(); + doReturn(newMedia).when(mapper).mapToMedia(any(), any()); + + AddAudioMetadataRequest addAudioMetadataRequest = new AddAudioMetadataRequest(); + addAudioMetadataRequest.setStartedAt(STARTED_AT); + addAudioMetadataRequest.setEndedAt(ENDED_AT); + addAudioMetadataRequest.setFileSize(100L); + addAudioMetadataRequest.setCases(Collections.emptyList()); + + audioService.versionUpload(List.of(exisingMediaVersion), + addAudioMetadataRequest, + UUID.randomUUID().toString(), + "checksum", + PersistableFactory.getUserAccountTestData().someMinimal()); + + var adminActionPropertiesCaptor = ArgumentCaptor.forClass(ApplyAdminActionComponent.AdminActionProperties.class); + verify(applyAdminActionComponent).applyAdminActionTo(any(), adminActionPropertiesCaptor.capture()); + verifyNoMoreInteractions(applyAdminActionComponent); + + ApplyAdminActionComponent.AdminActionProperties adminActionProperties = adminActionPropertiesCaptor.getValue(); + assertNull(adminActionProperties.ticketReference()); + assertEquals("Prior version had no admin action, so no details are available", adminActionProperties.comments()); + assertNull(adminActionProperties.hiddenReason()); + } + + @Test + void versionUpload_shouldInvokeHideAllFunctionalityWithCopiedAdminActionDetailsIfExistingMediaIsHiddenWithExistingAdminAction() { + MediaEntity exisingMediaVersion = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(100) + .isHidden(true) + .chronicleId("100") + .antecedentId(null) + .build() + .getEntity(); + + ObjectHiddenReasonEntity objectHiddenReason = new ObjectHiddenReasonEntity(); + ObjectAdminActionEntity adminAction = PersistableFactory.getObjectAdminActionTestData().someMinimalBuilder() + .media(exisingMediaVersion) + .comments("Some comments") + .ticketReference("Some ticket reference") + .objectHiddenReason(objectHiddenReason) + .build() + .getEntity(); + exisingMediaVersion.setObjectAdminAction(adminAction); + + MediaEntity newMedia = PersistableFactory.getMediaTestData() + .someMinimalBuilder() + .id(101) + .chronicleId("100") + .antecedentId("100") + .build() + .getEntity(); + doReturn(newMedia).when(mapper).mapToMedia(any(), any()); + + AddAudioMetadataRequest addAudioMetadataRequest = new AddAudioMetadataRequest(); + addAudioMetadataRequest.setStartedAt(STARTED_AT); + addAudioMetadataRequest.setEndedAt(ENDED_AT); + addAudioMetadataRequest.setFileSize(100L); + addAudioMetadataRequest.setCases(Collections.emptyList()); + + audioService.versionUpload(List.of(exisingMediaVersion), + addAudioMetadataRequest, + UUID.randomUUID().toString(), + "checksum", + PersistableFactory.getUserAccountTestData().someMinimal()); + + var adminActionPropertiesCaptor = ArgumentCaptor.forClass(ApplyAdminActionComponent.AdminActionProperties.class); + verify(applyAdminActionComponent).applyAdminActionTo(any(), adminActionPropertiesCaptor.capture()); + verifyNoMoreInteractions(applyAdminActionComponent); + + ApplyAdminActionComponent.AdminActionProperties adminActionProperties = adminActionPropertiesCaptor.getValue(); + assertEquals("Some ticket reference", adminActionProperties.ticketReference()); + assertEquals("Some comments", adminActionProperties.comments()); + assertEquals(objectHiddenReason, adminActionProperties.hiddenReason()); + } private AddAudioMetadataRequest setupVersionUploadTest(int endTimeOffset, long fileSize) { MediaEntity mediaEntity = mock(MediaEntity.class); diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplAdminMediaSearchTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplAdminMediaSearchTest.java deleted file mode 100644 index 3113c10b3e..0000000000 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplAdminMediaSearchTest.java +++ /dev/null @@ -1,204 +0,0 @@ -package uk.gov.hmcts.darts.audio.service.impl; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import uk.gov.hmcts.darts.audio.mapper.GetAdminMediaResponseMapper; -import uk.gov.hmcts.darts.audio.model.AdminActionRequest; -import uk.gov.hmcts.darts.audio.model.MediaHideRequest; -import uk.gov.hmcts.darts.audio.model.MediaHideResponse; -import uk.gov.hmcts.darts.audio.validation.MediaHideOrShowValidator; -import uk.gov.hmcts.darts.audio.validation.SearchMediaValidator; -import uk.gov.hmcts.darts.audit.api.AuditApi; -import uk.gov.hmcts.darts.authorisation.component.UserIdentity; -import uk.gov.hmcts.darts.common.entity.MediaEntity; -import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; -import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; -import uk.gov.hmcts.darts.common.entity.UserAccountEntity; -import uk.gov.hmcts.darts.common.helper.CurrentTimeHelper; -import uk.gov.hmcts.darts.common.repository.MediaRepository; -import uk.gov.hmcts.darts.common.repository.ObjectAdminActionRepository; -import uk.gov.hmcts.darts.common.repository.ObjectHiddenReasonRepository; -import uk.gov.hmcts.darts.common.repository.TransformedMediaRepository; - -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.List; -import java.util.Optional; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -@SuppressWarnings({"PMD.ExcessiveImports"}) -class MediaRequestServiceImplAdminMediaSearchTest { - - @InjectMocks - private MediaRequestServiceImpl mediaRequestService; - - @Mock - private MediaRepository mediaRepository; - @Mock - private TransformedMediaRepository mockTransformedMediaRepository; - - @Mock - private MediaHideOrShowValidator mediaHideOrShowValidator; - - @Mock - private ObjectAdminActionRepository objectAdminActionRepository; - - @Mock - private ObjectHiddenReasonRepository objectHiddenReasonRepository; - - @Mock - private UserIdentity userIdentity; - - @Mock - private CurrentTimeHelper currentTimeHelper; - - @Mock - private SearchMediaValidator searchMediaValidator; - - @Mock - private AuditApi auditApi; - - @Captor - ArgumentCaptor objectAdminActionEntityArgumentCaptor; - - @Captor - ArgumentCaptor mediaEntityArgumentCaptor; - - private MockedStatic adminMediaSearchResponseMapperMockedStatic; - - @AfterEach - void finish() { - if (adminMediaSearchResponseMapperMockedStatic != null) { - adminMediaSearchResponseMapperMockedStatic.close(); - } - } - - @Test - void testMediaDocumentHide() { - MediaHideRequest request = new MediaHideRequest(); - request.setIsHidden(true); - setupTestMediaHide(request); - } - - @Test - void testMediaHideDefaultIsHidden() { - MediaHideRequest request = new MediaHideRequest(); - setupTestMediaHide(request); - } - - void setupTestMediaHide(MediaHideRequest request) { - OffsetDateTime testTime = OffsetDateTime.of(2023, 1, 1, 10, 0, 0, 0, ZoneOffset.UTC); - when(currentTimeHelper.currentOffsetDateTime()).thenReturn(testTime); - - adminMediaSearchResponseMapperMockedStatic = Mockito.mockStatic(GetAdminMediaResponseMapper.class); - - Integer hideOrShowTranscriptionDocument = 343; - Integer reasonId = 555; - - String ticketReference = "my ticket reference"; - String comments = "my comments"; - - AdminActionRequest adminActionRequest = new AdminActionRequest(); - adminActionRequest.setReasonId(reasonId); - adminActionRequest.setTicketReference(ticketReference); - adminActionRequest.setComments(comments); - - request.setAdminAction(adminActionRequest); - - UserAccountEntity userAccountEntity = mock(UserAccountEntity.class); - - MediaEntity mediaEntity = new MediaEntity(); - when(mediaRepository.findByIdIncludeDeleted(hideOrShowTranscriptionDocument)).thenReturn(Optional.of(mediaEntity)); - when(userIdentity.getUserAccount()).thenReturn(userAccountEntity); - - when(mediaRepository.saveAndFlush(mediaEntityArgumentCaptor.capture())).thenReturn(mediaEntity); - ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); - ObjectHiddenReasonEntity objectHiddenReasonEntity = new ObjectHiddenReasonEntity(); - MediaHideResponse expectedResponse = new MediaHideResponse(); - - when(objectHiddenReasonRepository.findById(reasonId)).thenReturn(Optional.of(objectHiddenReasonEntity)); - - when(objectAdminActionRepository.saveAndFlush(objectAdminActionEntityArgumentCaptor.capture())).thenReturn(objectAdminActionEntity); - - adminMediaSearchResponseMapperMockedStatic.when( - () -> GetAdminMediaResponseMapper.mapHideOrShowResponse(mediaEntity, objectAdminActionEntity)) - .thenReturn(expectedResponse); - - - //run the test - MediaHideResponse actualResponse - = mediaRequestService.adminHideOrShowMediaById(hideOrShowTranscriptionDocument, request); - - - // make the assertion - Assertions.assertTrue(mediaEntityArgumentCaptor.getValue().isHidden()); - Assertions.assertEquals(expectedResponse, actualResponse); - Assertions.assertEquals(request.getAdminAction().getComments(), objectAdminActionEntityArgumentCaptor.getValue().getComments()); - Assertions.assertEquals(request.getAdminAction().getReasonId(), reasonId); - Assertions.assertFalse(objectAdminActionEntityArgumentCaptor.getValue().isMarkedForManualDeletion()); - Assertions.assertNotNull(objectAdminActionEntityArgumentCaptor.getValue().getHiddenBy()); - Assertions.assertNotNull(objectAdminActionEntityArgumentCaptor.getValue().getHiddenDateTime()); - Assertions.assertNull(objectAdminActionEntityArgumentCaptor.getValue().getMarkedForManualDelBy()); - Assertions.assertNull(objectAdminActionEntityArgumentCaptor.getValue().getMarkedForManualDelDateTime()); - } - - @Test - void testMediaShow() { - adminMediaSearchResponseMapperMockedStatic = Mockito.mockStatic(GetAdminMediaResponseMapper.class); - - MediaHideRequest request = new MediaHideRequest(); - request.setIsHidden(false); - - Integer hideOrShowTranscriptionDocument = 343; - Integer reasonId = 555; - - AdminActionRequest adminActionRequest = new AdminActionRequest(); - adminActionRequest.setReasonId(reasonId); - request.setAdminAction(adminActionRequest); - - MediaEntity mediaEntity = new MediaEntity(); - when(mediaRepository.findByIdIncludeDeleted(hideOrShowTranscriptionDocument)).thenReturn(Optional.of(mediaEntity)); - - Integer objectAdminActionEntityId = 1000; - Integer objectAdminActionEntityId1 = 1001; - - ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); - objectAdminActionEntity.setId(objectAdminActionEntityId); - ObjectAdminActionEntity objectAdminActionEntity1 = new ObjectAdminActionEntity(); - objectAdminActionEntity1.setId(objectAdminActionEntityId1); - - when(mediaRepository.saveAndFlush(mediaEntityArgumentCaptor.capture())).thenReturn(mediaEntity); - when(objectAdminActionRepository - .findByMedia_Id(hideOrShowTranscriptionDocument)).thenReturn(List.of(objectAdminActionEntity, objectAdminActionEntity1)); - - MediaHideResponse expectedResponse = new MediaHideResponse(); - - adminMediaSearchResponseMapperMockedStatic.when(() -> GetAdminMediaResponseMapper.mapHideOrShowResponse(mediaEntity, null)) - .thenReturn(expectedResponse); - - - // run the test - MediaHideResponse actualResponse - = mediaRequestService.adminHideOrShowMediaById(hideOrShowTranscriptionDocument, request); - - // make the assertion - Assertions.assertFalse(mediaEntityArgumentCaptor.getValue().isHidden()); - Assertions.assertEquals(expectedResponse, actualResponse); - verify(objectAdminActionRepository, times(1)).deleteById(objectAdminActionEntityId); - verify(objectAdminActionRepository, times(1)).deleteById(objectAdminActionEntityId1); - } -} \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplTest.java index 040ffc9b7d..8b773c0939 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/MediaRequestServiceImplTest.java @@ -14,9 +14,7 @@ import uk.gov.hmcts.darts.audio.exception.AudioApiError; import uk.gov.hmcts.darts.audio.exception.AudioRequestsApiError; import uk.gov.hmcts.darts.audio.mapper.GetTransformedMediaDetailsMapper; -import uk.gov.hmcts.darts.audio.model.AdminActionRequest; import uk.gov.hmcts.darts.audio.model.AudioRequestBeingProcessedFromArchiveQueryResult; -import uk.gov.hmcts.darts.audio.model.MediaHideRequest; import uk.gov.hmcts.darts.audio.validation.AudioMediaPatchRequestValidator; import uk.gov.hmcts.darts.audio.validation.MediaHideOrShowValidator; import uk.gov.hmcts.darts.audiorequests.model.AudioNonAccessedResponse; @@ -54,7 +52,6 @@ import java.io.IOException; import java.time.OffsetDateTime; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -82,15 +79,11 @@ import static uk.gov.hmcts.darts.audit.api.AuditActivity.AUDIO_PLAYBACK; import static uk.gov.hmcts.darts.audit.api.AuditActivity.CHANGE_AUDIO_OWNERSHIP; import static uk.gov.hmcts.darts.audit.api.AuditActivity.EXPORT_AUDIO; -import static uk.gov.hmcts.darts.audit.api.AuditActivity.HIDE_AUDIO; import static uk.gov.hmcts.darts.audit.api.AuditActivity.REQUEST_AUDIO; -import static uk.gov.hmcts.darts.audit.api.AuditActivity.UNHIDE_AUDIO; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.FAILURE_CHECKSUM_FAILED; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.STORED; import static uk.gov.hmcts.darts.notification.api.NotificationApi.NotificationTemplate.AUDIO_REQUEST_PROCESSING; import static uk.gov.hmcts.darts.notification.api.NotificationApi.NotificationTemplate.AUDIO_REQUEST_PROCESSING_ARCHIVE; -import static uk.gov.hmcts.darts.test.common.data.ObjectAdminActionTestData.objectAdminActionWithDefaults; -import static uk.gov.hmcts.darts.test.common.data.ObjectHiddenReasonTestData.classified; import static uk.gov.hmcts.darts.util.EntityIdPopulator.withIdsPopulated; @ExtendWith(MockitoExtension.class) @@ -798,33 +791,4 @@ void doesNotAuditWhenOwnerNotChanged() { verifyNoInteractions(auditApi); } - @Test - @SuppressWarnings("java:S1874") - void auditsWhenAudioHidden() { - var media = withIdsPopulated(mediaTestData.someMinimalMedia()); - media.setHidden(false); - when(mediaRepository.findByIdIncludeDeleted(any())).thenReturn(Optional.of(media)); - when(objectHiddenReasonRepository.findById(any())).thenReturn(Optional.of(classified())); - - var mediaHideRequest = new MediaHideRequest() - .isHidden(true) - .adminAction(new AdminActionRequest().reasonId(1)); - - mediaRequestService.adminHideOrShowMediaById(media.getId(), mediaHideRequest); - - verify(auditApi).record(HIDE_AUDIO); - } - - @Test - @SuppressWarnings("java:S1874") - void auditsWhenAudioMadeVisible() { - var media = withIdsPopulated(mediaTestData.someMinimalMedia()); - media.setHidden(true); - when(mediaRepository.findByIdIncludeDeleted(any())).thenReturn(Optional.of(media)); - when(objectAdminActionRepository.findByMedia_Id(any())).thenReturn(Arrays.asList(objectAdminActionWithDefaults())); - - mediaRequestService.adminHideOrShowMediaById(media.getId(), new MediaHideRequest().isHidden(false)); - - verify(auditApi).record(UNHIDE_AUDIO, "Ticket reference: Ticket-123, Comments: some comment"); - } } \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/common/entity/MediaEntityTest.java b/src/test/java/uk/gov/hmcts/darts/common/entity/MediaEntityTest.java new file mode 100644 index 0000000000..f36cceb4c8 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/darts/common/entity/MediaEntityTest.java @@ -0,0 +1,77 @@ +package uk.gov.hmcts.darts.common.entity; + +import org.junit.jupiter.api.Test; +import uk.gov.hmcts.darts.test.common.data.PersistableFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MediaEntityTest { + + @Test + void getObjectAdminAction_shouldReturnEmptyOptional_whenNoAdminActionsAreSet() { + MediaEntity media = PersistableFactory.getMediaTestData().someMinimalBuilder() + .build() + .getEntity(); + + Optional adminActionOptional = media.getObjectAdminAction(); + assertTrue(adminActionOptional.isEmpty()); + } + + @Test + void getObjectAdminAction_shouldReturnAdminAction_whenSingularAdminActionIsSet() { + ObjectAdminActionEntity adminAction = PersistableFactory.getObjectAdminActionTestData().someMinimal(); + MediaEntity media = PersistableFactory.getMediaTestData().someMinimalBuilder() + .objectAdminActions(Collections.singletonList(adminAction)) + .build() + .getEntity(); + + Optional adminActionOptional = media.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + + ObjectAdminActionEntity retrievedAdminAction = adminActionOptional.get(); + assertEquals(adminAction, retrievedAdminAction); + } + + @Test + void getObjectAdminAction_shouldReturnFirstAdminAction_whenMultipleAdminActionsAreSet() { + ObjectAdminActionEntity firstAdminAction = PersistableFactory.getObjectAdminActionTestData().someMinimal(); + ObjectAdminActionEntity otherAdminAction = PersistableFactory.getObjectAdminActionTestData().someMinimal(); + + MediaEntity media = PersistableFactory.getMediaTestData().someMinimalBuilder() + .objectAdminActions(List.of(firstAdminAction, otherAdminAction)) + .build() + .getEntity(); + + Optional adminActionOptional = media.getObjectAdminAction(); + assertTrue(adminActionOptional.isPresent()); + + ObjectAdminActionEntity retrievedAdminAction = adminActionOptional.get(); + assertEquals(firstAdminAction, retrievedAdminAction); + } + + @Test + void setObjectAdminAction_shouldSetSingularAdminAction_whenSomeAlreadyExist() { + ObjectAdminActionEntity existingAdminAction = PersistableFactory.getObjectAdminActionTestData().someMinimal(); + ObjectAdminActionEntity newAdminAction = PersistableFactory.getObjectAdminActionTestData().someMinimal(); + + List adminActions = new ArrayList<>(); + adminActions.add(existingAdminAction); + + MediaEntity media = PersistableFactory.getMediaTestData().someMinimalBuilder() + .objectAdminActions(adminActions) + .build() + .getEntity(); + + media.setObjectAdminAction(newAdminAction); + + assertEquals(1, media.getObjectAdminActions().size()); + assertEquals(newAdminAction, media.getObjectAdminActions().getFirst()); + } + +} \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourthouseTestData.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourthouseTestData.java index 14e71b94ca..dc45940759 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourthouseTestData.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourthouseTestData.java @@ -1,16 +1,54 @@ package uk.gov.hmcts.darts.test.common.data; import uk.gov.hmcts.darts.common.entity.CourthouseEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.test.common.data.builder.TestCourthouseEntity; + +import java.time.OffsetDateTime; +import java.util.UUID; import static org.apache.commons.lang3.RandomStringUtils.random; import static uk.gov.hmcts.darts.test.common.data.UserAccountTestData.minimalUserAccount; -public final class CourthouseTestData { +public final class CourthouseTestData implements Persistable { - private CourthouseTestData() { + private static final OffsetDateTime NOW = OffsetDateTime.now(); + @Override + public CourthouseEntity someMinimal() { + return someMinimalBuilder().build().getEntity(); } + @Override + public TestCourthouseEntity.TestCourthouseEntityBuilderRetrieve someMinimalBuilderHolder() { + var builderRetrieve = new TestCourthouseEntity.TestCourthouseEntityBuilderRetrieve(); + + UserAccountEntity someUser = PersistableFactory.getUserAccountTestData().someMinimal(); + + builderRetrieve.getBuilder() + .courthouseName("SOME COURTHOUSE (%s)".formatted(UUID.randomUUID().toString())) + .createdDateTime(NOW) + .lastModifiedDateTime(NOW) + .createdBy(someUser) + .lastModifiedBy(someUser) + .displayName("Some Courthouse"); + + return builderRetrieve; + } + + @Override + public TestCourthouseEntity.TestCourthouseEntityBuilder someMinimalBuilder() { + return someMinimalBuilderHolder().getBuilder(); + } + + /** + * Create a "minimal" courthouse entity. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static CourthouseEntity someMinimalCourthouse() { var postfix = random(10, false, true); var courtHouse = new CourthouseEntity(); @@ -23,6 +61,12 @@ public static CourthouseEntity someMinimalCourthouse() { return courtHouse; } + /** + * Create a courthouse with the given name. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static CourthouseEntity createCourthouseWithName(String name) { var courthouse = someMinimalCourthouse(); courthouse.setCourthouseName(name); @@ -30,10 +74,17 @@ public static CourthouseEntity createCourthouseWithName(String name) { return courthouse; } + /** + * Create a courthouse with the given name and display name. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static CourthouseEntity createCourthouseWithDifferentNameAndDisplayName(String name, String displayName) { var courthouse = someMinimalCourthouse(); courthouse.setCourthouseName(name); courthouse.setDisplayName(displayName); return courthouse; } + } \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourtroomTestData.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourtroomTestData.java index 14e1f425a2..2a5df71b47 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourtroomTestData.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/CourtroomTestData.java @@ -2,17 +2,46 @@ import uk.gov.hmcts.darts.common.entity.CourthouseEntity; import uk.gov.hmcts.darts.common.entity.CourtroomEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.test.common.data.builder.TestCourtroomEntity; +import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.UUID; import static org.apache.commons.lang3.RandomStringUtils.random; import static uk.gov.hmcts.darts.test.common.data.CourthouseTestData.createCourthouseWithName; import static uk.gov.hmcts.darts.test.common.data.UserAccountTestData.minimalUserAccount; -public final class CourtroomTestData { +public final class CourtroomTestData implements Persistable { - private CourtroomTestData() { + private static final OffsetDateTime NOW = OffsetDateTime.now(); + @Override + public CourtroomEntity someMinimal() { + return someMinimalBuilder().build().getEntity(); + } + + @Override + public TestCourtroomEntity.TestCourtroomEntityBuilderRetrieve someMinimalBuilderHolder() { + var builderRetrieve = new TestCourtroomEntity.TestCourtroomEntityBuilderRetrieve(); + + UserAccountEntity someUser = PersistableFactory.getUserAccountTestData().someMinimal(); + + builderRetrieve.getBuilder() + .courthouse(PersistableFactory.getCourthouseTestData().someMinimal()) + .name("SOME COURTROOM (%s)".formatted(UUID.randomUUID().toString())) + .createdDateTime(NOW) + .createdBy(someUser); + + return builderRetrieve; + } + + @Override + public TestCourtroomEntity.TestCourtroomEntityBuilder someMinimalBuilder() { + return someMinimalBuilderHolder().getBuilder(); } public static CourtroomEntity someMinimalCourtRoom() { @@ -34,4 +63,5 @@ public static CourtroomEntity createCourtRoomWithNameAtCourthouse(CourthouseEnti courtroom.setName(name); return courtroom; } + } \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/MediaTestData.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/MediaTestData.java index a707d7dfea..dc52cc8231 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/MediaTestData.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/MediaTestData.java @@ -2,12 +2,12 @@ import uk.gov.hmcts.darts.common.entity.CourtroomEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.retention.enums.RetentionConfidenceScoreEnum; import uk.gov.hmcts.darts.test.common.TestUtils; import uk.gov.hmcts.darts.test.common.data.builder.TestMediaEntity; import java.time.OffsetDateTime; -import java.util.ArrayList; import static java.time.OffsetDateTime.now; import static org.apache.commons.codec.digest.DigestUtils.md5; @@ -21,23 +21,47 @@ public final class MediaTestData implements Persistable()); - return builder; - } - - @Override - public TestMediaEntity.TestMediaEntityBuilder someMinimalBuilder() { - return someMinimalBuilderHolder().getBuilder(); - } } \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/ObjectAdminActionTestData.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/ObjectAdminActionTestData.java index 75e197d369..bf5651d556 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/ObjectAdminActionTestData.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/ObjectAdminActionTestData.java @@ -1,23 +1,55 @@ package uk.gov.hmcts.darts.test.common.data; import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.test.common.data.builder.TestObjectAdminActionEntity; import static java.time.OffsetDateTime.now; import static uk.gov.hmcts.darts.test.common.data.ObjectHiddenReasonTestData.publicInterestImmunity; import static uk.gov.hmcts.darts.test.common.data.UserAccountTestData.minimalUserAccount; -public final class ObjectAdminActionTestData { +public final class ObjectAdminActionTestData + implements Persistable { - private ObjectAdminActionTestData() { + @Override + public ObjectAdminActionEntity someMinimal() { + return someMinimalBuilder().build().getEntity(); + } + + @Override + public TestObjectAdminActionEntity.TestObjectAdminActionEntityBuilderRetrieve someMinimalBuilderHolder() { + var builderRetrieve = new TestObjectAdminActionEntity.TestObjectAdminActionEntityBuilderRetrieve(); + + builderRetrieve.getBuilder() + .media(PersistableFactory.getMediaTestData().someMinimal()) + .markedForManualDeletion(false); + + return builderRetrieve; + } + @Override + public TestObjectAdminActionEntity.TestObjectAdminActionEntityBuilder someMinimalBuilder() { + return someMinimalBuilderHolder().getBuilder(); } + /** + * Create a "minimal" object admin action entity. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static ObjectAdminActionEntity minimalObjectAdminAction() { var action = new ObjectAdminActionEntity(); action.setObjectHiddenReason(publicInterestImmunity()); return action; } + /** + * Create an object admin action entity with some (arbitrary) default values. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static ObjectAdminActionEntity objectAdminActionWithDefaults() { var action = minimalObjectAdminAction(); action.setComments("some comment"); diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/PersistableFactory.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/PersistableFactory.java index fbe54aec15..dd81f2b41c 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/PersistableFactory.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/PersistableFactory.java @@ -70,4 +70,20 @@ public static RetentionConfidenceCategoryMapperTestData getRetentionConfidenceCa return new RetentionConfidenceCategoryMapperTestData(); } + public static UserAccountTestData getUserAccountTestData() { + return new UserAccountTestData(); + } + + public static CourthouseTestData getCourthouseTestData() { + return new CourthouseTestData(); + } + + public static CourtroomTestData getCourtroomTestData() { + return new CourtroomTestData(); + } + + public static ObjectAdminActionTestData getObjectAdminActionTestData() { + return new ObjectAdminActionTestData(); + } + } \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/UserAccountTestData.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/UserAccountTestData.java index dd4cdde03f..519204b317 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/UserAccountTestData.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/UserAccountTestData.java @@ -3,17 +3,49 @@ import uk.gov.hmcts.darts.common.entity.CourthouseEntity; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.common.enums.SecurityRoleEnum; +import uk.gov.hmcts.darts.test.common.data.builder.TestUserAccountEntity; +import java.time.OffsetDateTime; import java.util.Set; import static uk.gov.hmcts.darts.test.common.data.SecurityGroupTestData.buildGroupForRoleAndCourthouse; -public final class UserAccountTestData { +public final class UserAccountTestData + implements Persistable { - private UserAccountTestData() { + private static final OffsetDateTime NOW = OffsetDateTime.now(); + @Override + public UserAccountEntity someMinimal() { + return someMinimalBuilder().build().getEntity(); } + @Override + public TestUserAccountEntity.TestUserAccountEntityBuilderRetrieve someMinimalBuilderHolder() { + var builder = new TestUserAccountEntity.TestUserAccountEntityBuilderRetrieve(); + + builder.getBuilder() + .createdDateTime(NOW) + .lastModifiedDateTime(NOW) + .isSystemUser(false) + .active(true) + .userFullName("Some User Full Name"); + + return builder; + } + + @Override + public TestUserAccountEntity.TestUserAccountEntityBuilder someMinimalBuilder() { + return someMinimalBuilderHolder().getBuilder(); + } + + /** + * Create a "minimal" user account entity. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static UserAccountEntity minimalUserAccount() { var userAccount = new UserAccountEntity(); userAccount.setActive(true); @@ -23,6 +55,12 @@ public static UserAccountEntity minimalUserAccount() { return userAccount; } + /** + * Create a user account entity with specified properties. + * @deprecated Tests should be refactored to use the entity creation methods provided by the {@link Persistable} interface. + */ + @Deprecated + @SuppressWarnings("java:S1133") // suppress sonar warning about deprecated methods public static UserAccountEntity buildUserWithRoleFor(SecurityRoleEnum role, CourthouseEntity courthouse) { var securityGroupEntity = buildGroupForRoleAndCourthouse(role, courthouse); var userAccount = minimalUserAccount(); @@ -30,4 +68,5 @@ public static UserAccountEntity buildUserWithRoleFor(SecurityRoleEnum role, Cour userAccount.setSecurityGroupEntities(Set.of(securityGroupEntity)); return userAccount; } -} \ No newline at end of file + +} diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourthouseEntity.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourthouseEntity.java new file mode 100644 index 0000000000..560f6cabd5 --- /dev/null +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourthouseEntity.java @@ -0,0 +1,81 @@ +package uk.gov.hmcts.darts.test.common.data.builder; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.hibernate.AssertionFailure; +import uk.gov.hmcts.darts.common.entity.CourthouseEntity; +import uk.gov.hmcts.darts.common.entity.CourtroomEntity; +import uk.gov.hmcts.darts.common.entity.RegionEntity; +import uk.gov.hmcts.darts.common.entity.SecurityGroupEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.lang.reflect.InvocationTargetException; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +// TestClassWithoutTestCases suppression: This is not a test class. +// ConstructorCallsOverridableMethod suppression: If this proves to be a demonstrable problem, we can change the object creation approach. For now, it is fine. +@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.ConstructorCallsOverridableMethod"}) +@RequiredArgsConstructor +public class TestCourthouseEntity extends CourthouseEntity implements DbInsertable { + + @lombok.Builder + public TestCourthouseEntity(Integer id, + Integer code, + String courthouseName, + List courtrooms, + Set securityGroups, + Set regions, + String displayName, + String courthouseObjectId, + String folderPath, + UserAccountEntity createdBy, + OffsetDateTime createdDateTime, + UserAccountEntity lastModifiedBy, + OffsetDateTime lastModifiedDateTime) { + setId(id); + setCode(code); + setCourthouseName(courthouseName); + setCourtrooms(courtrooms != null ? courtrooms : new ArrayList<>()); + setSecurityGroups(securityGroups != null ? securityGroups : new LinkedHashSet<>()); + setRegions(regions != null ? regions : new LinkedHashSet<>()); + setDisplayName(displayName); + setCourthouseObjectId(courthouseObjectId); + setFolderPath(folderPath); + setCreatedBy(createdBy); + setCreatedDateTime(createdDateTime); + setLastModifiedBy(lastModifiedBy); + setLastModifiedDateTime(lastModifiedDateTime); + } + + @Override + public CourthouseEntity getEntity() { + try { + CourthouseEntity courthouseEntity = new CourthouseEntity(); + BeanUtils.copyProperties(courthouseEntity, this); + return courthouseEntity; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionFailure("Assumed that there would be no error on mapping data", e); + } + } + + public static class TestCourthouseEntityBuilderRetrieve implements BuilderHolder { + + private final TestCourthouseEntity.TestCourthouseEntityBuilder builder = TestCourthouseEntity.builder(); + + @Override + public TestCourthouseEntity build() { + return builder.build(); + } + + @Override + public TestCourthouseEntity.TestCourthouseEntityBuilder getBuilder() { + return builder; + } + } + +} + diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourtroomEntity.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourtroomEntity.java new file mode 100644 index 0000000000..f465eedcc1 --- /dev/null +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestCourtroomEntity.java @@ -0,0 +1,58 @@ +package uk.gov.hmcts.darts.test.common.data.builder; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.hibernate.AssertionFailure; +import uk.gov.hmcts.darts.common.entity.CourthouseEntity; +import uk.gov.hmcts.darts.common.entity.CourtroomEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.lang.reflect.InvocationTargetException; +import java.time.OffsetDateTime; + +// TestClassWithoutTestCases suppression: This is not a test class. +// ConstructorCallsOverridableMethod suppression: If this proves to be a demonstrable problem, we can change the object creation approach. For now, it is fine. +@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.ConstructorCallsOverridableMethod"}) +@RequiredArgsConstructor +public class TestCourtroomEntity extends CourtroomEntity implements DbInsertable { + + @lombok.Builder + public TestCourtroomEntity(Integer id, + String name, + CourthouseEntity courthouse, + UserAccountEntity createdBy, + OffsetDateTime createdDateTime) { + setId(id); + setName(name); + setCourthouse(courthouse); + setCreatedBy(createdBy); + setCreatedDateTime(createdDateTime); + } + + @Override + public CourtroomEntity getEntity() { + try { + CourtroomEntity courtroomEntity = new CourtroomEntity(); + BeanUtils.copyProperties(courtroomEntity, this); + return courtroomEntity; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionFailure("Assumed that there would be no error on mapping data", e); + } + } + + public static class TestCourtroomEntityBuilderRetrieve implements BuilderHolder { + + private final TestCourtroomEntity.TestCourtroomEntityBuilder builder = TestCourtroomEntity.builder(); + + @Override + public TestCourtroomEntity build() { + return builder.build(); + } + + @Override + public TestCourtroomEntity.TestCourtroomEntityBuilder getBuilder() { + return builder; + } + } + +} \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestMediaEntity.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestMediaEntity.java index e271d0ef1b..702abf2364 100644 --- a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestMediaEntity.java +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestMediaEntity.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.List; +@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.ConstructorCallsOverridableMethod"}) @RequiredArgsConstructor public class TestMediaEntity extends MediaEntity implements DbInsertable { @@ -29,7 +30,7 @@ public TestMediaEntity(Integer id, CourtroomEntity courtroom, boolean isDeleted, Boolean isCurrent, UserAccountEntity deletedBy, OffsetDateTime deletedTimestamp, String mediaStatus, List hearingList, OffsetDateTime retainUntilTs, - List adminActionReasons, RetentionConfidenceScoreEnum retConfScore, + List objectAdminActions, RetentionConfidenceScoreEnum retConfScore, String retConfReason, OffsetDateTime createdDateTime, UserAccountEntity createdBy, OffsetDateTime lastModifiedDateTime, UserAccountEntity lastModifiedBy) { @@ -59,7 +60,7 @@ public TestMediaEntity(Integer id, CourtroomEntity courtroom, setMediaStatus(mediaStatus); setHearingList(hearingList != null ? hearingList : new ArrayList<>()); setRetainUntilTs(retainUntilTs); - setAdminActionReasons(adminActionReasons != null ? adminActionReasons : new ArrayList<>()); + setObjectAdminActions(objectAdminActions != null ? objectAdminActions : new ArrayList<>()); setRetConfScore(retConfScore); setRetConfReason(retConfReason); setCreatedDateTime(createdDateTime); diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestObjectAdminActionEntity.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestObjectAdminActionEntity.java new file mode 100644 index 0000000000..ef80967e0b --- /dev/null +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestObjectAdminActionEntity.java @@ -0,0 +1,78 @@ +package uk.gov.hmcts.darts.test.common.data.builder; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.hibernate.AssertionFailure; +import uk.gov.hmcts.darts.common.entity.AnnotationDocumentEntity; +import uk.gov.hmcts.darts.common.entity.CaseDocumentEntity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.ObjectAdminActionEntity; +import uk.gov.hmcts.darts.common.entity.ObjectHiddenReasonEntity; +import uk.gov.hmcts.darts.common.entity.TranscriptionDocumentEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.lang.reflect.InvocationTargetException; +import java.time.OffsetDateTime; + +// TestClassWithoutTestCases suppression: This is not a test class. +// ConstructorCallsOverridableMethod suppression: If this proves to be a demonstrable problem, we can change the object creation approach. For now, it is fine. +@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.ConstructorCallsOverridableMethod"}) +@RequiredArgsConstructor +public class TestObjectAdminActionEntity extends ObjectAdminActionEntity implements DbInsertable { + @lombok.Builder + public TestObjectAdminActionEntity(Integer id, + AnnotationDocumentEntity annotationDocument, + CaseDocumentEntity caseDocument, + MediaEntity media, + TranscriptionDocumentEntity transcriptionDocument, + ObjectHiddenReasonEntity objectHiddenReason, + UserAccountEntity hiddenBy, + OffsetDateTime hiddenDateTime, + boolean markedForManualDeletion, + UserAccountEntity markedForManualDelBy, + OffsetDateTime markedForManualDelDateTime, + String ticketReference, + String comments) { + setId(id); + setAnnotationDocument(annotationDocument); + setCaseDocument(caseDocument); + setMedia(media); + setTranscriptionDocument(transcriptionDocument); + setObjectHiddenReason(objectHiddenReason); + setHiddenBy(hiddenBy); + setHiddenDateTime(hiddenDateTime); + setMarkedForManualDeletion(markedForManualDeletion); + setMarkedForManualDelBy(markedForManualDelBy); + setMarkedForManualDelDateTime(markedForManualDelDateTime); + setTicketReference(ticketReference); + setComments(comments); + } + + @Override + public ObjectAdminActionEntity getEntity() { + try { + ObjectAdminActionEntity objectAdminActionEntity = new ObjectAdminActionEntity(); + BeanUtils.copyProperties(objectAdminActionEntity, this); + return objectAdminActionEntity; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionFailure("Assumed that there would be no error on mapping data", e); + } + } + + public static class TestObjectAdminActionEntityBuilderRetrieve + implements BuilderHolder { + + private final TestObjectAdminActionEntity.TestObjectAdminActionEntityBuilder builder = TestObjectAdminActionEntity.builder(); + + @Override + public TestObjectAdminActionEntity build() { + return builder.build(); + } + + @Override + public TestObjectAdminActionEntity.TestObjectAdminActionEntityBuilder getBuilder() { + return builder; + } + } + +} \ No newline at end of file diff --git a/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestUserAccountEntity.java b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestUserAccountEntity.java new file mode 100644 index 0000000000..198b16f27a --- /dev/null +++ b/src/testCommon/java/uk/gov/hmcts/darts/test/common/data/builder/TestUserAccountEntity.java @@ -0,0 +1,94 @@ +package uk.gov.hmcts.darts.test.common.data.builder; + +import lombok.RequiredArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.hibernate.AssertionFailure; +import uk.gov.hmcts.darts.common.entity.SecurityGroupEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.lang.reflect.InvocationTargetException; +import java.time.OffsetDateTime; +import java.util.Set; + +// TestClassWithoutTestCases suppression: This is not a test class. +// ConstructorCallsOverridableMethod suppression: If this proves to be a demonstrable problem, we can change the object creation approach. For now, it is fine. +@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.ConstructorCallsOverridableMethod"}) +@RequiredArgsConstructor +public class TestUserAccountEntity extends UserAccountEntity implements DbInsertable { + + @lombok.Builder + public TestUserAccountEntity( + Integer id, + String dmObjectId, + String userName, + String userFullName, + String emailAddress, + String userDescription, + Boolean active, + OffsetDateTime lastLoginTime, + String accountGuid, + Boolean isSystemUser, + Set securityGroupEntities, + String userOsName, + String userLdapDomainName, + String userGlobalUniqueId, + String userLoginName, + String userLoginDomain, + Short userState, + OffsetDateTime createdDateTime, + UserAccountEntity createdBy, + OffsetDateTime lastModifiedDateTime, + UserAccountEntity lastModifiedBy + ) { + setId(id); + setDmObjectId(dmObjectId); + setUserName(userName); + setUserFullName(userFullName); + setEmailAddress(emailAddress); + setUserDescription(userDescription); + setActive(active); + setLastLoginTime(lastLoginTime); + setAccountGuid(accountGuid); + setIsSystemUser(isSystemUser); + setSecurityGroupEntities(securityGroupEntities); + setUserOsName(userOsName); + setUserLdapDomainName(userLdapDomainName); + setUserGlobalUniqueId(userGlobalUniqueId); + setUserLoginName(userLoginName); + setUserLoginDomain(userLoginDomain); + setUserState(userState); + setCreatedDateTime(createdDateTime); + setCreatedBy(createdBy); + setLastModifiedDateTime(lastModifiedDateTime); + setLastModifiedBy(lastModifiedBy); + } + + @Override + public UserAccountEntity getEntity() { + try { + UserAccountEntity userAccountEntity = new UserAccountEntity(); + BeanUtils.copyProperties(userAccountEntity, this); + userAccountEntity.setActive(this.isActive()); // Needed as BeanUtils gets confused with the getter/setting naming on this Boolean field + return userAccountEntity; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionFailure("Assumed that there would be no error on mapping data", e); + } + } + + public static class TestUserAccountEntityBuilderRetrieve + implements BuilderHolder { + + private TestUserAccountEntity.TestUserAccountEntityBuilder builder = TestUserAccountEntity.builder(); + + @Override + public TestUserAccountEntity build() { + return builder.build(); + } + + @Override + public TestUserAccountEntity.TestUserAccountEntityBuilder getBuilder() { + return builder; + } + } + +} \ No newline at end of file