From ca7ff2648973281a538f6bf987f995c3a6d3e3c3 Mon Sep 17 00:00:00 2001 From: Jack Maloney Date: Wed, 18 Dec 2024 15:03:32 +0000 Subject: [PATCH 1/2] DMP-2542 Unlink expired cases from media --- .../CaseExpiryDeletionAutomatedTaskITest.java | 71 ++++++++++++++++++- .../testutils/stubs/MediaLinkedCaseStub.java | 22 ++++++ .../common/repository/HearingRepository.java | 17 +++++ .../repository/MediaLinkedCaseRepository.java | 14 ++++ .../hearings/service/HearingsService.java | 2 + .../service/impl/HearingsServiceImpl.java | 23 ++++++ .../impl/CaseExpiryDeletionAutomatedTask.java | 8 ++- .../service/impl/HearingsServiceImplTest.java | 58 ++++++++++++++- .../CaseExpiryDeletionAutomatedTaskTest.java | 26 ++++--- 9 files changed, 222 insertions(+), 19 deletions(-) create mode 100644 src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/MediaLinkedCaseStub.java diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskITest.java b/src/integrationTest/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskITest.java index 7e90d1aaaf..37f989194f 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskITest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskITest.java @@ -15,6 +15,7 @@ import uk.gov.hmcts.darts.common.entity.EventEntity; import uk.gov.hmcts.darts.common.entity.EventLinkedCaseEntity; import uk.gov.hmcts.darts.common.entity.HearingEntity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; import uk.gov.hmcts.darts.common.entity.ProsecutorEntity; import uk.gov.hmcts.darts.common.entity.TranscriptionCommentEntity; import uk.gov.hmcts.darts.common.entity.TranscriptionEntity; @@ -33,6 +34,7 @@ import uk.gov.hmcts.darts.testutils.PostgresIntegrationBase; import uk.gov.hmcts.darts.testutils.stubs.EventLinkedCaseStub; import uk.gov.hmcts.darts.testutils.stubs.EventStub; +import uk.gov.hmcts.darts.testutils.stubs.MediaLinkedCaseStub; import uk.gov.hmcts.darts.testutils.stubs.TranscriptionStub; import uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum; @@ -59,6 +61,7 @@ class CaseExpiryDeletionAutomatedTaskITest extends PostgresIntegrationBase { private final CaseExpiryDeletionAutomatedTask caseExpiryDeletionAutomatedTask; private final EventLinkedCaseStub eventLinkedCaseStub; + private final MediaLinkedCaseStub mediaLinkedCaseStub; private int caseIndex; @Test @@ -74,7 +77,7 @@ void positiveRetentionDatePassed() { @Test @DisplayName("Two cases linked to the same event, one case has passed retention date, the other has not. Event should not be anonymised") - void retentionDatePassedForOneCaseButNotAnotherEventNotAnoymised() { + void retentionDatePassedForOneCaseButNotAnotherEventNotAnonymised() { CourtCaseEntity courtCase1 = createCase(-1, CaseRetentionStatus.COMPLETE); CourtCaseEntity courtCase2 = createCase(-1, CaseRetentionStatus.PENDING); @@ -90,7 +93,7 @@ void retentionDatePassedForOneCaseButNotAnotherEventNotAnoymised() { @Test @DisplayName("Two cases linked to the same event, both cases have passed retention date. Event should be anonymised") - void retentionDatePassedForBothCaseLinkedEventsAnoymised() { + void retentionDatePassedForBothCaseLinkedEventsAnonymised() { CourtCaseEntity courtCase1 = createCase(-1, CaseRetentionStatus.COMPLETE); CourtCaseEntity courtCase2 = createCase(-1, CaseRetentionStatus.COMPLETE); @@ -148,6 +151,48 @@ void positiveMultipleToAnonymiseAndSomeNotTo() { assertCase(courtCase5.getId(), false); } + @Test + @DisplayName("Two cases linked to the same media, one case has passed retention date, the other has not. Media link should not be removed from hearings") + void retentionDatePassedForOneCaseButNotAnotherMediaLinkNotRemovedFromHearing() { + CourtCaseEntity courtCase1 = createCase(-1, CaseRetentionStatus.COMPLETE); + CourtCaseEntity courtCase2 = createCase(1, CaseRetentionStatus.COMPLETE); + + createMediaForHearing(courtCase1.getHearings().get(0)); + // Link same media to second case + linkExistingMediaToHearing(courtCase1.getHearings().get(0).getMediaList(), courtCase2.getHearings().getFirst(), courtCase2); + + caseExpiryDeletionAutomatedTask.preRunTask(); + caseExpiryDeletionAutomatedTask.runTask(); + + List hearingsToAssert = List.of(courtCase1.getHearings().get(0), courtCase2.getHearings().get(0)); + + hearingsToAssert.forEach(h -> { + HearingEntity hearing = dartsDatabase.getHearingRepository().findByCaseIdWithMediaList(h.getCourtCase().getId()).get(); + assertThat(hearing.getMediaList()).size().isEqualTo(1); + assertThat(hearing.getMediaList().getFirst().getId()).isEqualTo(1); + }); + } + + @Test + @DisplayName("Two cases linked to the same media, both cases have passed retention date. Media link should be removed from hearings") + void retentionDatePassedForBothCasesThenMediaLinkRemovedFromHearing() { + CourtCaseEntity courtCase1 = createCase(-1, CaseRetentionStatus.COMPLETE); + CourtCaseEntity courtCase2 = createCase(-1, CaseRetentionStatus.COMPLETE); + + createMediaForHearing(courtCase1.getHearings().get(0)); + // Link same media to second case + linkExistingMediaToHearing(courtCase1.getHearings().get(0).getMediaList(), courtCase2.getHearings().getFirst(), courtCase2); + + caseExpiryDeletionAutomatedTask.preRunTask(); + caseExpiryDeletionAutomatedTask.runTask(); + + List hearingsToAssert = List.of(courtCase1.getHearings().get(0), courtCase2.getHearings().get(0)); + + hearingsToAssert.forEach(h -> { + HearingEntity hearing = dartsDatabase.getHearingRepository().findByCaseIdWithMediaList(h.getCourtCase().getId()).get(); + assertThat(hearing.getMediaList()).isEmpty(); + }); + } private void assertCase(int caseId, boolean isAnonymised, int... excludeEventIds) { transactionalUtil.executeInTransaction(() -> { @@ -356,7 +401,6 @@ private CourtCaseEntity createCase(final long daysUntilRetention, final CaseRete caseEntity.addProsecutor(createProsecutorEntity(caseEntity)); HearingEntity hearing = createHearing(caseEntity); - createHearing(caseEntity); caseEntity = dartsDatabase.getCaseRepository().save(caseEntity); @@ -392,6 +436,27 @@ private HearingEntity createHearing(CourtCaseEntity caseEntity) { return hearingEntity; } + private void createMediaForHearing(HearingEntity hearingEntity) { + MediaEntity mediaEntity = dartsDatabase.getMediaStub().createMediaEntity(hearingEntity.getCourtCase().getCourthouse().getCourthouseName(), + "1", + OffsetDateTime.parse("2024-01-01T00:00:00Z"), + OffsetDateTime.parse("2024-01-01T00:00:00Z"), + 1, + "MP2"); + hearingEntity.setMediaList(new ArrayList<>(List.of(mediaEntity))); + mediaLinkedCaseStub.createCaseLinkedMedia(mediaEntity, hearingEntity.getCourtCase()); + dartsDatabase.getHearingRepository().save(hearingEntity); + } + + private void linkExistingMediaToHearing(List mediaList, HearingEntity hearingEntity, CourtCaseEntity courtCase) { + transactionalUtil.executeInTransaction(() -> { + hearingEntity.setMediaList(mediaList); + dartsDatabase.getHearingRepository().save(hearingEntity); + + mediaLinkedCaseStub.createCaseLinkedMedia(mediaList.get(0), courtCase); + }); + } + private void createMediaRequest(HearingEntity hearingEntity) { MediaRequestEntity mediaRequestEntity = dartsDatabase.getMediaRequestStub() .createAndSaveMediaRequestEntity(hearingEntity.getCreatedBy(), hearingEntity); diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/MediaLinkedCaseStub.java b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/MediaLinkedCaseStub.java new file mode 100644 index 0000000000..290f331752 --- /dev/null +++ b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/MediaLinkedCaseStub.java @@ -0,0 +1,22 @@ +package uk.gov.hmcts.darts.testutils.stubs; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import uk.gov.hmcts.darts.common.entity.CourtCaseEntity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; +import uk.gov.hmcts.darts.common.entity.MediaLinkedCaseEntity; +import uk.gov.hmcts.darts.common.repository.MediaLinkedCaseRepository; + +@Component +@RequiredArgsConstructor +public class MediaLinkedCaseStub { + + private final MediaLinkedCaseRepository mediaLinkedCaseRepository; + + public MediaLinkedCaseEntity createCaseLinkedMedia(MediaEntity media, CourtCaseEntity caseEntity) { + MediaLinkedCaseEntity mediaLinkedCaseEntity = new MediaLinkedCaseEntity(); + mediaLinkedCaseEntity.setMedia(media); + mediaLinkedCaseEntity.setCourtCase(caseEntity); + return mediaLinkedCaseRepository.save(mediaLinkedCaseEntity); + } +} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java b/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java index 56745c998b..ccf23d86d2 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java +++ b/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java @@ -39,6 +39,14 @@ public interface HearingRepository extends JpaRepository ) List findHearingIdsByEventId(Integer eventId); + @Query(""" + SELECT h FROM HearingEntity h + JOIN h.mediaList media + WHERE media.id = :mediaId + """ + ) + Optional> findHearingIdsByMediaId(Integer mediaId); + @Query(""" SELECT h FROM HearingEntity h, CourthouseEntity ch, CourtroomEntity cr, CourtCaseEntity case WHERE ch.courthouseName = upper(:courthouse) @@ -76,4 +84,13 @@ WHERE he.courtroom.id in (select courtroom.id from CourtroomEntity where courtho List findHearingDetails(List courthouseIds, String caseNumber, String courtroomName, LocalDate startDate, LocalDate endDate, Integer numberOfRecords); + + @Query(""" + SELECT hearing + FROM HearingEntity hearing, CourtCaseEntity case + LEFT JOIN FETCH hearing.mediaList + WHERE case.id = :caseId + AND hearing.courtCase = case + """) + Optional findByCaseIdWithMediaList(Integer caseId); } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/common/repository/MediaLinkedCaseRepository.java b/src/main/java/uk/gov/hmcts/darts/common/repository/MediaLinkedCaseRepository.java index 0afd67fedb..290ed890ef 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/repository/MediaLinkedCaseRepository.java +++ b/src/main/java/uk/gov/hmcts/darts/common/repository/MediaLinkedCaseRepository.java @@ -1,6 +1,7 @@ package uk.gov.hmcts.darts.common.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import uk.gov.hmcts.darts.common.entity.CourtCaseEntity; import uk.gov.hmcts.darts.common.entity.MediaEntity; @@ -12,10 +13,23 @@ @Repository public interface MediaLinkedCaseRepository extends JpaRepository { + List findAllByCourtCase(CourtCaseEntity courtCase); + List findByMedia(MediaEntity media); List findByMediaAndSource(MediaEntity mediaEntity, MediaLinkedCaseSourceType source); boolean existsByMediaAndCourtCase(MediaEntity media, CourtCaseEntity courtCase); + @Query(""" + SELECT COUNT(DISTINCT cc) = (COUNT(cc.isDataAnonymised) filter (where cc.isDataAnonymised = true)) + FROM MediaLinkedCaseEntity mlc + LEFT JOIN CourtCaseEntity cc + ON (mlc.courtCase = cc + or (cc.courthouse.courthouseName = mlc.courthouseName and cc.caseNumber = mlc.caseNumber)) + WHERE mlc.media = :mediaEntity + group by mlc.media + """ + ) + boolean areAllAssociatedCasesAnonymised(MediaEntity mediaEntity); } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/hearings/service/HearingsService.java b/src/main/java/uk/gov/hmcts/darts/hearings/service/HearingsService.java index cd59d31cd6..4c134b915f 100644 --- a/src/main/java/uk/gov/hmcts/darts/hearings/service/HearingsService.java +++ b/src/main/java/uk/gov/hmcts/darts/hearings/service/HearingsService.java @@ -19,4 +19,6 @@ public interface HearingsService { List getTranscriptsByHearingId(Integer hearingId); List getAnnotationsByHearingId(Integer hearingId); + + void removeMediaLinkToHearing(Integer courtCaseId); } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java index a00357477b..fffde6b5ba 100644 --- a/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java @@ -14,6 +14,7 @@ import uk.gov.hmcts.darts.common.repository.AnnotationRepository; import uk.gov.hmcts.darts.common.repository.EventRepository; import uk.gov.hmcts.darts.common.repository.HearingRepository; +import uk.gov.hmcts.darts.common.repository.MediaLinkedCaseRepository; import uk.gov.hmcts.darts.common.repository.TranscriptionRepository; import uk.gov.hmcts.darts.hearings.exception.HearingApiError; import uk.gov.hmcts.darts.hearings.mapper.GetAnnotationsResponseMapper; @@ -37,6 +38,7 @@ public class HearingsServiceImpl implements HearingsService { private final GetHearingResponseMapper getHearingResponseMapper; private final HearingRepository hearingRepository; + private final MediaLinkedCaseRepository mediaLinkedCaseRepository; private final TranscriptionRepository transcriptionRepository; private final EventRepository eventRepository; private final AnnotationRepository annotationRepository; @@ -98,6 +100,27 @@ public List getAnnotationsByHearingId(Integer hearingId) { return GetAnnotationsResponseMapper.mapToAnnotations(annotations, hearingId); } + @Override + public void removeMediaLinkToHearing(Integer courtCaseId) { + hearingRepository.findByCaseIdWithMediaList(courtCaseId).ifPresent(hearing -> + hearing.getMediaList().forEach(media -> { + // Check all cases linked to a hearing have been expired/anonymised + if (!mediaLinkedCaseRepository.areAllAssociatedCasesAnonymised(media)) { + log.info("Media {} link not removed for case id {} as not all associated cases are expired", media.getId(), courtCaseId); + } else { + hearingRepository.findHearingIdsByMediaId(media.getId()).ifPresent(hearingsForMedia -> + hearingsForMedia.forEach(hearingForMedia -> { + hearingForMedia.setMediaList(null); + hearingRepository.save(hearingForMedia); + log.info("Media id {} link removed for hearing id {} on the expiry of case id {}", + media.getId(), hearingForMedia.getId(), courtCaseId); + }) + ); + } + }) + ); + } + private void validateCaseIsNotExpiredFromHearingId(Integer hearingId) { Optional hearingEntity = hearingRepository.findById(hearingId); hearingEntity diff --git a/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java b/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java index c1b519ef44..e5772c01ba 100644 --- a/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java +++ b/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java @@ -10,6 +10,7 @@ import uk.gov.hmcts.darts.common.repository.AutomatedTaskRepository; import uk.gov.hmcts.darts.common.repository.CaseRepository; import uk.gov.hmcts.darts.common.service.DataAnonymisationService; +import uk.gov.hmcts.darts.hearings.service.HearingsService; import uk.gov.hmcts.darts.log.api.LogApi; import uk.gov.hmcts.darts.task.api.AutomatedTaskName; import uk.gov.hmcts.darts.task.config.CaseExpiryDeletionAutomatedTaskConfig; @@ -30,6 +31,7 @@ public class CaseExpiryDeletionAutomatedTask private final CurrentTimeHelper currentTimeHelper; private final DataAnonymisationService dataAnonymisationService; + private final HearingsService hearingsService; private final CaseRepository caseRepository; private final UserIdentity userAccountService; @@ -38,11 +40,14 @@ public CaseExpiryDeletionAutomatedTask(AutomatedTaskRepository automatedTaskRepo CurrentTimeHelper currentTimeHelper, CaseRepository caseRepository, LogApi logApi, LockService lockService, - DataAnonymisationService dataAnonymisationService, UserIdentity userAccountService) { + DataAnonymisationService dataAnonymisationService, + HearingsService hearingsService, + UserIdentity userAccountService) { super(automatedTaskRepository, automatedTaskConfigurationProperties, logApi, lockService); this.currentTimeHelper = currentTimeHelper; this.caseRepository = caseRepository; this.dataAnonymisationService = dataAnonymisationService; + this.hearingsService = hearingsService; this.userAccountService = userAccountService; } @@ -62,6 +67,7 @@ public void runTask() { try { log.info("Anonymising case with id: {} because the criteria for retention has been met.", courtCaseId); dataAnonymisationService.anonymiseCourtCaseById(userAccount, courtCaseId, false); + hearingsService.removeMediaLinkToHearing(courtCaseId); } catch (Exception e) { log.error("An error occurred while anonymising case with id: {}", courtCaseId, e); } diff --git a/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java index d1eee90e09..1f5b4ae0d8 100644 --- a/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java @@ -13,11 +13,13 @@ import uk.gov.hmcts.darts.common.entity.EventEntity; import uk.gov.hmcts.darts.common.entity.EventHandlerEntity; import uk.gov.hmcts.darts.common.entity.HearingEntity; +import uk.gov.hmcts.darts.common.entity.MediaEntity; import uk.gov.hmcts.darts.common.exception.DartsApiException; import uk.gov.hmcts.darts.common.repository.AnnotationRepository; import uk.gov.hmcts.darts.common.repository.EventRepository; import uk.gov.hmcts.darts.common.repository.HearingReportingRestrictionsRepository; import uk.gov.hmcts.darts.common.repository.HearingRepository; +import uk.gov.hmcts.darts.common.repository.MediaLinkedCaseRepository; import uk.gov.hmcts.darts.common.repository.TranscriptionRepository; import uk.gov.hmcts.darts.common.util.CommonTestDataUtil; import uk.gov.hmcts.darts.hearings.mapper.GetHearingResponseMapper; @@ -32,7 +34,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -41,11 +46,12 @@ class HearingsServiceImplTest { @Mock HearingRepository hearingRepository; @Mock + MediaLinkedCaseRepository mediaLinkedCaseRepository; + @Mock EventRepository eventRepository; @Mock HearingReportingRestrictionsRepository hearingReportingRestrictionsRepository; - @Mock TranscriptionRepository transcriptionRepository; @@ -64,6 +70,7 @@ void setUp() { service = new HearingsServiceImpl( getHearingResponseMapper, hearingRepository, + mediaLinkedCaseRepository, transcriptionRepository, eventRepository, annotationRepository, @@ -145,6 +152,54 @@ void testGetEventsResponseCaseIsExpired() { assertThat(exception.getMessage()).isEqualTo("Case has expired."); } + @Test + void testRemoveMediaLinkToHearing() { + MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); + HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); + hearingEntity.setMediaList(List.of(mediaEntity)); + + when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.of(hearingEntity)); + when(mediaLinkedCaseRepository.areAllAssociatedCasesAnonymised(any())).thenReturn(true); + when(hearingRepository.findHearingIdsByMediaId(mediaEntity.getId())).thenReturn(Optional.of(List.of(hearingEntity))); + + service.removeMediaLinkToHearing(hearingEntity.getCourtCase().getId()); + verify(hearingRepository).save(hearingEntity); + } + + @Test + void testDoNotRemoveMediaLinkToHearingWhenNonExpiredAssociatedCases() { + MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); + HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); + hearingEntity.setMediaList(List.of(mediaEntity)); + + when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.of(hearingEntity)); + when(mediaLinkedCaseRepository.areAllAssociatedCasesAnonymised(any())).thenReturn(false); + + service.removeMediaLinkToHearing(hearingEntity.getCourtCase().getId()); + verifyNoMoreInteractions(hearingRepository); + } + + @Test + void testHandleHearingWithNoMediaToUnlink() { + MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); + HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); + + when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.of(hearingEntity)); + + service.removeMediaLinkToHearing(hearingEntity.getCourtCase().getId()); + verifyNoMoreInteractions(hearingRepository); + } + + @Test + void testHandleHearingWithNoHearingsWithMediaToUnlink() { + HearingEntity hearingEntity = createHearingEntity(true); + + when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.empty()); + + service.removeMediaLinkToHearing(hearingEntity.getCourtCase().getId()); + verifyNoMoreInteractions(hearingRepository); + } + private HearingEntity createHearingEntity(boolean isHearingActual) { CourthouseEntity courthouseEntity = CommonTestDataUtil.createCourthouse("swansea"); CourtroomEntity courtroomEntity = CommonTestDataUtil.createCourtroom(courthouseEntity, "1"); @@ -154,4 +209,5 @@ private HearingEntity createHearingEntity(boolean isHearingActual) { return CommonTestDataUtil.createHearing(caseEntity, courtroomEntity, LocalDate.now(), isHearingActual); } + } \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java b/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java index 743bbf3d9b..2bd0930759 100644 --- a/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java +++ b/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java @@ -13,6 +13,7 @@ import uk.gov.hmcts.darts.common.repository.AutomatedTaskRepository; import uk.gov.hmcts.darts.common.repository.CaseRepository; import uk.gov.hmcts.darts.common.service.DataAnonymisationService; +import uk.gov.hmcts.darts.hearings.service.HearingsService; import uk.gov.hmcts.darts.log.api.LogApi; import uk.gov.hmcts.darts.task.config.CaseExpiryDeletionAutomatedTaskConfig; import uk.gov.hmcts.darts.task.service.LockService; @@ -47,6 +48,8 @@ class CaseExpiryDeletionAutomatedTaskTest { private DataAnonymisationService dataAnonymisationService; @Mock private UserIdentity userIdentity; + @Mock + private HearingsService hearingsService; @InjectMocks @@ -73,20 +76,15 @@ void runTask() { verify(currentTimeHelper, times(1)) .currentOffsetDateTime(); - verify(dataAnonymisationService, times(1)) - .anonymiseCourtCaseById(userAccount, 1, false); - verify(dataAnonymisationService, times(1)) - .anonymiseCourtCaseById(userAccount, 2, false); - verify(dataAnonymisationService, times(1)) - .anonymiseCourtCaseById(userAccount, 3, false); - + verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 1, false); + verify(hearingsService).removeMediaLinkToHearing(1); + verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 2, false); + verify(hearingsService).removeMediaLinkToHearing(2); + verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 3, false); + verify(hearingsService).removeMediaLinkToHearing(3); - verify(caseRepository, times(1)) - .findCaseIdsToBeAnonymised(offsetDateTime.minus(duration), Limit.of(5)); - - verify(caseExpiryDeletionAutomatedTask, times(1)) - .getAutomatedTaskBatchSize(); - verify(userIdentity, times(1)) - .getUserAccount(); + verify(caseRepository).findCaseIdsToBeAnonymised(offsetDateTime.minus(duration), Limit.of(5)); + verify(caseExpiryDeletionAutomatedTask).getAutomatedTaskBatchSize(); + verify(userIdentity).getUserAccount(); } } From bf76f70e76878beaa9a4b46afbdc25e7da81b153 Mon Sep 17 00:00:00 2001 From: Jack Maloney Date: Wed, 18 Dec 2024 16:27:47 +0000 Subject: [PATCH 2/2] Address PR comments --- .../common/repository/HearingRepository.java | 2 +- .../hmcts/darts/hearings/api/HearingApi.java | 7 +++++++ .../hearings/api/impl/HearingApiImpl.java | 19 +++++++++++++++++++ .../service/impl/HearingsServiceImpl.java | 14 ++++++-------- .../impl/CaseExpiryDeletionAutomatedTask.java | 10 +++++----- .../service/impl/HearingsServiceImplTest.java | 10 +++++----- .../CaseExpiryDeletionAutomatedTaskTest.java | 10 +++++----- 7 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/darts/hearings/api/HearingApi.java create mode 100644 src/main/java/uk/gov/hmcts/darts/hearings/api/impl/HearingApiImpl.java diff --git a/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java b/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java index ccf23d86d2..f19589fd18 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java +++ b/src/main/java/uk/gov/hmcts/darts/common/repository/HearingRepository.java @@ -45,7 +45,7 @@ public interface HearingRepository extends JpaRepository WHERE media.id = :mediaId """ ) - Optional> findHearingIdsByMediaId(Integer mediaId); + List findHearingIdsByMediaId(Integer mediaId); @Query(""" SELECT h FROM HearingEntity h, CourthouseEntity ch, CourtroomEntity cr, CourtCaseEntity case diff --git a/src/main/java/uk/gov/hmcts/darts/hearings/api/HearingApi.java b/src/main/java/uk/gov/hmcts/darts/hearings/api/HearingApi.java new file mode 100644 index 0000000000..c8062defc2 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/hearings/api/HearingApi.java @@ -0,0 +1,7 @@ +package uk.gov.hmcts.darts.hearings.api; + +public interface HearingApi { + + void removeMediaLinkToHearing(Integer courtCaseId); + +} diff --git a/src/main/java/uk/gov/hmcts/darts/hearings/api/impl/HearingApiImpl.java b/src/main/java/uk/gov/hmcts/darts/hearings/api/impl/HearingApiImpl.java new file mode 100644 index 0000000000..d1221cdca8 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/hearings/api/impl/HearingApiImpl.java @@ -0,0 +1,19 @@ +package uk.gov.hmcts.darts.hearings.api.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import uk.gov.hmcts.darts.hearings.api.HearingApi; +import uk.gov.hmcts.darts.hearings.service.HearingsService; + +@Service +@RequiredArgsConstructor +public class HearingApiImpl implements HearingApi { + + private final HearingsService hearingsService; + + @Override + public void removeMediaLinkToHearing(Integer courtCaseId) { + hearingsService.removeMediaLinkToHearing(courtCaseId); + } + +} diff --git a/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java b/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java index fffde6b5ba..c395399605 100644 --- a/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImpl.java @@ -108,14 +108,12 @@ public void removeMediaLinkToHearing(Integer courtCaseId) { if (!mediaLinkedCaseRepository.areAllAssociatedCasesAnonymised(media)) { log.info("Media {} link not removed for case id {} as not all associated cases are expired", media.getId(), courtCaseId); } else { - hearingRepository.findHearingIdsByMediaId(media.getId()).ifPresent(hearingsForMedia -> - hearingsForMedia.forEach(hearingForMedia -> { - hearingForMedia.setMediaList(null); - hearingRepository.save(hearingForMedia); - log.info("Media id {} link removed for hearing id {} on the expiry of case id {}", - media.getId(), hearingForMedia.getId(), courtCaseId); - }) - ); + hearingRepository.findHearingIdsByMediaId(media.getId()).forEach(hearingForMedia -> { + hearingForMedia.setMediaList(null); + hearingRepository.save(hearingForMedia); + log.info("Media id {} link removed for hearing id {} on the expiry of case id {}", + media.getId(), hearingForMedia.getId(), courtCaseId); + }); } }) ); diff --git a/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java b/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java index e5772c01ba..253c1f12f8 100644 --- a/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java +++ b/src/main/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTask.java @@ -10,7 +10,7 @@ import uk.gov.hmcts.darts.common.repository.AutomatedTaskRepository; import uk.gov.hmcts.darts.common.repository.CaseRepository; import uk.gov.hmcts.darts.common.service.DataAnonymisationService; -import uk.gov.hmcts.darts.hearings.service.HearingsService; +import uk.gov.hmcts.darts.hearings.api.HearingApi; import uk.gov.hmcts.darts.log.api.LogApi; import uk.gov.hmcts.darts.task.api.AutomatedTaskName; import uk.gov.hmcts.darts.task.config.CaseExpiryDeletionAutomatedTaskConfig; @@ -31,7 +31,7 @@ public class CaseExpiryDeletionAutomatedTask private final CurrentTimeHelper currentTimeHelper; private final DataAnonymisationService dataAnonymisationService; - private final HearingsService hearingsService; + private final HearingApi hearingApi; private final CaseRepository caseRepository; private final UserIdentity userAccountService; @@ -41,13 +41,13 @@ public CaseExpiryDeletionAutomatedTask(AutomatedTaskRepository automatedTaskRepo CaseRepository caseRepository, LogApi logApi, LockService lockService, DataAnonymisationService dataAnonymisationService, - HearingsService hearingsService, + HearingApi hearingApi, UserIdentity userAccountService) { super(automatedTaskRepository, automatedTaskConfigurationProperties, logApi, lockService); this.currentTimeHelper = currentTimeHelper; this.caseRepository = caseRepository; this.dataAnonymisationService = dataAnonymisationService; - this.hearingsService = hearingsService; + this.hearingApi = hearingApi; this.userAccountService = userAccountService; } @@ -67,7 +67,7 @@ public void runTask() { try { log.info("Anonymising case with id: {} because the criteria for retention has been met.", courtCaseId); dataAnonymisationService.anonymiseCourtCaseById(userAccount, courtCaseId, false); - hearingsService.removeMediaLinkToHearing(courtCaseId); + hearingApi.removeMediaLinkToHearing(courtCaseId); } catch (Exception e) { log.error("An error occurred while anonymising case with id: {}", courtCaseId, e); } diff --git a/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java index 1f5b4ae0d8..c14f4bbdd7 100644 --- a/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/hearings/service/impl/HearingsServiceImplTest.java @@ -153,21 +153,21 @@ void testGetEventsResponseCaseIsExpired() { } @Test - void testRemoveMediaLinkToHearing() { + void removeMediaLinkToHearing_shouldRemoveLinkToHearing_whenAllAssociatedCasesAreAnonymised() { MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); hearingEntity.setMediaList(List.of(mediaEntity)); when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.of(hearingEntity)); when(mediaLinkedCaseRepository.areAllAssociatedCasesAnonymised(any())).thenReturn(true); - when(hearingRepository.findHearingIdsByMediaId(mediaEntity.getId())).thenReturn(Optional.of(List.of(hearingEntity))); + when(hearingRepository.findHearingIdsByMediaId(mediaEntity.getId())).thenReturn(List.of(hearingEntity)); service.removeMediaLinkToHearing(hearingEntity.getCourtCase().getId()); verify(hearingRepository).save(hearingEntity); } @Test - void testDoNotRemoveMediaLinkToHearingWhenNonExpiredAssociatedCases() { + void removeMediaLinkToHearing_shouldNotRemoveLinkToHearing_whenAllAssociatedCasesAreNotAnonymised() { MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); hearingEntity.setMediaList(List.of(mediaEntity)); @@ -180,7 +180,7 @@ void testDoNotRemoveMediaLinkToHearingWhenNonExpiredAssociatedCases() { } @Test - void testHandleHearingWithNoMediaToUnlink() { + void removeMediaLinkToHearing_shouldDoNothing_whenHearingsWithNoMediaExistsToUnlink() { MediaEntity mediaEntity = CommonTestDataUtil.createMedia("T1234"); HearingEntity hearingEntity = mediaEntity.getHearingList().getFirst(); @@ -191,7 +191,7 @@ void testHandleHearingWithNoMediaToUnlink() { } @Test - void testHandleHearingWithNoHearingsWithMediaToUnlink() { + void removeMediaLinkToHearing_shouldDoNothing_whenNoHearingsExist() { HearingEntity hearingEntity = createHearingEntity(true); when(hearingRepository.findByCaseIdWithMediaList(hearingEntity.getCourtCase().getId())).thenReturn(Optional.empty()); diff --git a/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java b/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java index 2bd0930759..6ff39f7ed8 100644 --- a/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java +++ b/src/test/java/uk/gov/hmcts/darts/task/runner/impl/CaseExpiryDeletionAutomatedTaskTest.java @@ -13,7 +13,7 @@ import uk.gov.hmcts.darts.common.repository.AutomatedTaskRepository; import uk.gov.hmcts.darts.common.repository.CaseRepository; import uk.gov.hmcts.darts.common.service.DataAnonymisationService; -import uk.gov.hmcts.darts.hearings.service.HearingsService; +import uk.gov.hmcts.darts.hearings.api.HearingApi; import uk.gov.hmcts.darts.log.api.LogApi; import uk.gov.hmcts.darts.task.config.CaseExpiryDeletionAutomatedTaskConfig; import uk.gov.hmcts.darts.task.service.LockService; @@ -49,7 +49,7 @@ class CaseExpiryDeletionAutomatedTaskTest { @Mock private UserIdentity userIdentity; @Mock - private HearingsService hearingsService; + private HearingApi hearingApi; @InjectMocks @@ -77,11 +77,11 @@ void runTask() { .currentOffsetDateTime(); verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 1, false); - verify(hearingsService).removeMediaLinkToHearing(1); + verify(hearingApi).removeMediaLinkToHearing(1); verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 2, false); - verify(hearingsService).removeMediaLinkToHearing(2); + verify(hearingApi).removeMediaLinkToHearing(2); verify(dataAnonymisationService).anonymiseCourtCaseById(userAccount, 3, false); - verify(hearingsService).removeMediaLinkToHearing(3); + verify(hearingApi).removeMediaLinkToHearing(3); verify(caseRepository).findCaseIdsToBeAnonymised(offsetDateTime.minus(duration), Limit.of(5)); verify(caseExpiryDeletionAutomatedTask).getAutomatedTaskBatchSize();