diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/audio/repository/TransformedMediaRepositoryTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/audio/repository/TransformedMediaRepositoryTest.java index 3afe27b017..e89648ef41 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/audio/repository/TransformedMediaRepositoryTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/audio/repository/TransformedMediaRepositoryTest.java @@ -41,8 +41,8 @@ void closeHibernateSession() { void testFindTransformedMediaWithoutAnyParameters() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, - null, null, null, null, null); + null, null, null, + null, null, null, null, null); Assertions.assertEquals(generatedMediaEntities.size(), transformedMediaEntityList.size()); Assertions.assertTrue(transformedMediaStub.getTransformedMediaIds(transformedMediaEntityList) .containsAll(transformedMediaStub.getTransformedMediaIds(generatedMediaEntities))); @@ -52,8 +52,8 @@ void testFindTransformedMediaWithoutAnyParameters() { void testFindTransformedMediaWithId() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - generatedMediaEntities.get(0).getMediaRequest().getId(), - null, null, null, null, null, null, null); + generatedMediaEntities.get(0).getMediaRequest().getId(), + null, null, null, null, null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(0).getId(), transformedMediaEntityList.size()); } @@ -62,7 +62,7 @@ void testFindTransformedMediaWithId() { void testFindTransformedMediaWithCaseNumber() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, generatedMediaEntities.get(3).getMediaRequest().getHearing().getCourtCase().getCaseNumber(), null, null, null, null, null, null); + null, generatedMediaEntities.get(3).getMediaRequest().getHearing().getCourtCase().getCaseNumber(), null, null, null, null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(transformedMediaEntityList.get(0).getId(), generatedMediaEntities.get(3).getId()); } @@ -72,8 +72,8 @@ void testFindTransformedMediaWithCourtDisplayNameSubstringPrefixMatchOne() { int nameMatchIndex = 13; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, - TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPrefix(Integer.toString(nameMatchIndex)), null, null, null, null, null); + null, null, + TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPrefix(Integer.toString(nameMatchIndex)), null, null, null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); } @@ -95,8 +95,8 @@ void testFindTransformedMediaWithCourtDisplayNameSubstringPostFixMatchOne() { int nameMatchIndex = 13; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, - TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPostfix(Integer.toString(nameMatchIndex)), null, null, null, null, null); + null, null, + TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPostfix(Integer.toString(nameMatchIndex)), null, null, null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); } @@ -117,8 +117,8 @@ void testFindTransformedMediaWithCourtDisplayNameCaseInsensitiveSubstringPostFix void testFindTransformedMediaWithCourtDisplayNameSubstringMatchAll() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, - TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPrefix(), null, null, null, null, null); + null, null, + TransformedMediaSubStringQueryEnum.COURT_HOUSE.getQueryStringPrefix(), null, null, null, null, null); Assertions.assertEquals(GENERATION_COUNT, transformedMediaEntityList.size()); Assertions.assertTrue(transformedMediaStub.getTransformedMediaIds(transformedMediaEntityList) .containsAll(transformedMediaStub.getTransformedMediaIds(generatedMediaEntities))); @@ -128,8 +128,8 @@ void testFindTransformedMediaWithCourtDisplayNameSubstringMatchAll() { void testFindTransformedMediaWithHearingDate() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, - generatedMediaEntities.get(3).getMediaRequest().getHearing().getHearingDate(), null, null, null, null); + null, null, null, + generatedMediaEntities.get(3).getMediaRequest().getHearing().getHearingDate(), null, null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(3).getId(), transformedMediaEntityList.get(0).getId()); } @@ -139,8 +139,8 @@ void testFindTransformedMediaWithOwnerExact() { int nameMatchIndex = 3; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, - TransformedMediaSubStringQueryEnum.OWNER.getQueryString(Integer.toString(nameMatchIndex)), null, null, null); + null, null, null, null, + TransformedMediaSubStringQueryEnum.OWNER.getQueryString(Integer.toString(nameMatchIndex)), null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); } @@ -150,8 +150,8 @@ void testFindTransformedMediaWithOwnerPrefix() { int nameMatchIndex = 13; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, - TransformedMediaSubStringQueryEnum.OWNER.getQueryStringPostfix(Integer.toString(nameMatchIndex)), null, null, null); + null, null, null, null, + TransformedMediaSubStringQueryEnum.OWNER.getQueryStringPostfix(Integer.toString(nameMatchIndex)), null, null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); @@ -196,8 +196,8 @@ void testFindTransformedMediaWithOwnerCaseInsensitivePostfix() { void testFindTransformedMediaWithOwnerSubstringMatchAll() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, - TransformedMediaSubStringQueryEnum.OWNER.getQueryStringPostfix(), null, null, null); + null, null, null, null, + TransformedMediaSubStringQueryEnum.OWNER.getQueryStringPostfix(), null, null, null); Assertions.assertEquals(GENERATION_COUNT, transformedMediaEntityList.size()); Assertions.assertTrue(transformedMediaStub .getTransformedMediaIds(transformedMediaEntityList) @@ -209,8 +209,8 @@ void testFindTransformedMediaWithRequestedByExact() { int nameMatchIndex = 13; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, null, - TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryString(Integer.toString(nameMatchIndex)), null, null); + null, null, null, null, null, + TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryString(Integer.toString(nameMatchIndex)), null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); } @@ -220,8 +220,8 @@ void testFindTransformedMediaWithRequestedByPrefix() { int nameMatchIndex = 13; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, null, - TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryStringPrefix(Integer.toString(13)), null, null); + null, null, null, null, null, + TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryStringPrefix(Integer.toString(13)), null, null); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities.get(nameMatchIndex).getId(), transformedMediaEntityList.get(0).getId()); } @@ -263,8 +263,8 @@ void testFindTransformedMediaWithRequestedByCaseInsensitivePostfix() { void testFindTransformedMediaWithRequestedBySubstringMatchAll() { List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, null, - TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryStringPostfix(), null, null); + null, null, null, null, null, + TransformedMediaSubStringQueryEnum.REQUESTED_BY.getQueryStringPostfix(), null, null); Assertions.assertEquals(GENERATION_COUNT, transformedMediaEntityList.size()); Assertions.assertTrue(transformedMediaStub .getTransformedMediaIds(transformedMediaEntityList) @@ -276,9 +276,9 @@ void testFindTransformedMediaWithRequestedAtFromAndRequestedAtToSameDay() { int fromAtPosition = 3; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, null, null, - generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime(), - generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime()); + null, null, null, null, null, null, + generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime(), + generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime()); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(generatedMediaEntities .get(fromAtPosition).getId(), transformedMediaEntityList.get(0).getId()); @@ -289,8 +289,8 @@ void testFindTransformedMediaWithRequestedAtFrom() { int fromAtPosition = 3; List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia( - null, null, null, null, null, - null, generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime(), null); + null, null, null, null, null, + null, generatedMediaEntities.get(fromAtPosition).getMediaRequest().getCreatedDateTime(), null); Assertions.assertEquals(GENERATION_COUNT - fromAtPosition, transformedMediaEntityList.size()); Assertions.assertTrue(transformedMediaStub .getTransformedMediaIds(transformedMediaEntityList) @@ -314,13 +314,15 @@ void testFindTransformedMediaWithAllQueryParameters() { TransformedMediaEntity transformedMediaEntityFind = generatedMediaEntities.get(1); List transformedMediaEntityList = transformedMediaRepository.findTransformedMedia(transformedMediaEntityFind.getMediaRequest().getId(), transformedMediaEntityFind.getMediaRequest() - .getHearing().getCourtCase().getCaseNumber(), transformedMediaEntityFind.getMediaRequest() - .getHearing().getCourtroom().getCourthouse().getDisplayName(), transformedMediaEntityFind.getMediaRequest() - .getHearing().getHearingDate(), transformedMediaEntityFind.getMediaRequest() - .getCurrentOwner().getUserFullName(), transformedMediaEntityFind.getCreatedBy().getUserFullName(), transformedMediaEntityFind.getMediaRequest() - .getCreatedBy().getCreatedDateTime(), generatedMediaEntities.get(1).getCreatedDateTime()); + .getHearing().getCourtCase().getCaseNumber(), transformedMediaEntityFind.getMediaRequest() + .getHearing().getCourtroom().getCourthouse().getDisplayName(), + transformedMediaEntityFind.getMediaRequest() + .getHearing().getHearingDate(), transformedMediaEntityFind.getMediaRequest() + .getCurrentOwner().getUserFullName(), + transformedMediaEntityFind.getCreatedBy().getUserFullName(), + transformedMediaEntityFind.getMediaRequest() + .getCreatedBy().getCreatedDateTime(), generatedMediaEntities.get(1).getCreatedDateTime()); Assertions.assertEquals(1, transformedMediaEntityList.size()); Assertions.assertEquals(transformedMediaEntityFind.getId(), transformedMediaEntityList.get(0).getId()); } - } \ No newline at end of file diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/common/service/TransientObjectDirectoryServiceTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/common/service/TransientObjectDirectoryServiceTest.java index 946ddd132d..e1d69ab0da 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/common/service/TransientObjectDirectoryServiceTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/common/service/TransientObjectDirectoryServiceTest.java @@ -8,11 +8,13 @@ import uk.gov.hmcts.darts.audiorequests.model.AudioRequestType; import uk.gov.hmcts.darts.common.entity.TransformedMediaEntity; import uk.gov.hmcts.darts.common.entity.TransientObjectDirectoryEntity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; import uk.gov.hmcts.darts.testutils.IntegrationBase; import java.time.OffsetDateTime; import java.util.UUID; +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; @@ -37,7 +39,8 @@ void shouldSaveTransientDataLocation() { MediaRequestEntity mediaRequestEntity = mediaRequestService.getMediaRequestEntityById(mediaRequestEntity1.getId()); UUID blobId = UUID.fromString("f744a74f-83c0-47e4-8bb2-2fd4d2b68647"); - + UserAccountEntity userAccount = dartsDatabase.getUserAccountStub().createAuthorisedIntegrationTestUser(false, "NEWCASTLE"); + givenBearerTokenExists(userAccount.getEmailAddress()); TransformedMediaEntity transformedMediaEntity = transformedMediaHelper.createTransformedMediaEntity( mediaRequestEntity, "aFilename", @@ -45,6 +48,8 @@ void shouldSaveTransientDataLocation() { mediaRequestEntity.getEndTime(), 1000L ); + assertThat(transformedMediaEntity.getCreatedBy()).isEqualTo(mediaRequestEntity.getCreatedBy()); + assertThat(transformedMediaEntity.getLastModifiedBy()).isEqualTo(mediaRequestEntity.getCreatedBy()); TransientObjectDirectoryEntity transientObjectDirectoryEntity = transientObjectDirectoryService.saveTransientObjectDirectoryEntity( transformedMediaEntity, blobId @@ -62,5 +67,4 @@ void shouldSaveTransientDataLocation() { .isAfter(OffsetDateTime.parse("2023-07-06T16:05:00.000Z"))); assertNotNull(transientObjectDirectoryEntity.getLastModifiedBy()); } - } diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/PostgresIntegrationBase.java b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/PostgresIntegrationBase.java index a06c80b0f8..e63566d24d 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/PostgresIntegrationBase.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/PostgresIntegrationBase.java @@ -14,6 +14,8 @@ import uk.gov.hmcts.darts.testutils.stubs.DartsDatabaseStub; import uk.gov.hmcts.darts.testutils.stubs.DartsPersistence; +import java.util.List; + /** * Base class for integration tests running against a containerized Postgres with Testcontainers. */ @@ -50,6 +52,7 @@ public class PostgresIntegrationBase { ).withDatabaseName("darts") .withUsername("darts") .withPassword("darts"); + POSTGRES.setPortBindings(List.of("5433:5432")); } @DynamicPropertySource diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsDatabaseSaveStub.java b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsDatabaseSaveStub.java index c3e39dc90c..839f2710d9 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsDatabaseSaveStub.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/testutils/stubs/DartsDatabaseSaveStub.java @@ -101,4 +101,4 @@ public void updateCreatedByLastModifiedBy(CreatedModifiedBaseEntity createdModif public void saveAll(List caseManagementRetentionsWithEvents) { caseManagementRetentionsWithEvents.forEach(this::save); } -} +} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/audio/helper/TransformedMediaHelper.java b/src/main/java/uk/gov/hmcts/darts/audio/helper/TransformedMediaHelper.java index 5e979ab5c0..08c28d5fbf 100644 --- a/src/main/java/uk/gov/hmcts/darts/audio/helper/TransformedMediaHelper.java +++ b/src/main/java/uk/gov/hmcts/darts/audio/helper/TransformedMediaHelper.java @@ -96,14 +96,15 @@ public TransformedMediaEntity createTransformedMediaEntity(MediaRequestEntity me entity.setOutputFilename(filename); entity.setStartTime(startTime); entity.setEndTime(endTime); - entity.setCreatedBy(mediaRequest.getCreatedBy()); entity.setLastModifiedBy(mediaRequest.getCreatedBy()); + entity.setCreatedBy(mediaRequest.getCreatedBy()); entity.setOutputFormat(audioRequestOutputFormat); if (nonNull(fileSize)) { entity.setOutputFilesize(fileSize.intValue()); } - transformedMediaRepository.save(entity); - return entity; + //Ensures createdBy / LastModified does not get overridden by the @CreatedBy / @LastModifiedBy annotation + TransformedMediaEntity savedTM = transformedMediaRepository.save(entity); + return savedTM; } @SuppressWarnings({"PMD.CognitiveComplexity"}) diff --git a/src/main/java/uk/gov/hmcts/darts/authorisation/component/UserIdentity.java b/src/main/java/uk/gov/hmcts/darts/authorisation/component/UserIdentity.java index 9b8903cabe..ed37bd9c28 100644 --- a/src/main/java/uk/gov/hmcts/darts/authorisation/component/UserIdentity.java +++ b/src/main/java/uk/gov/hmcts/darts/authorisation/component/UserIdentity.java @@ -16,4 +16,6 @@ public interface UserIdentity { boolean userHasGlobalAccess(Set globalAccessRolest); List getListOfCourthouseIdsUserHasAccessTo(); + + Jwt getJwt(); } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/UserIdentityImpl.java b/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/UserIdentityImpl.java index e4bbe5e511..d60a3e0aa2 100644 --- a/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/UserIdentityImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/UserIdentityImpl.java @@ -62,7 +62,7 @@ public UserAccountEntity getUserAccount(Jwt jwt) { return userAccount; } - private Jwt getJwt() { + public Jwt getJwt() { if (SecurityContextHolder.getContext().getAuthentication() != null) { if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof Jwt jwt) { return jwt; diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBaseEntity.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBaseEntity.java index fd719bc7c2..f9e05325f6 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBaseEntity.java +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBaseEntity.java @@ -1,22 +1,26 @@ package uk.gov.hmcts.darts.common.entity.base; import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.Transient; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.envers.NotAudited; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.listener.UserAuditListener; import java.time.OffsetDateTime; @MappedSuperclass @Getter @Setter -public class CreatedBaseEntity { +@EntityListeners(UserAuditListener.class) +public class CreatedBaseEntity implements CreatedBy { @CreationTimestamp @Column(name = "created_ts") private OffsetDateTime createdDateTime; @@ -26,4 +30,11 @@ public class CreatedBaseEntity { @JoinColumn(name = "created_by") private UserAccountEntity createdBy; + public void setCreatedBy(UserAccountEntity userAccount) { + this.createdBy = userAccount; + this.skipUserAudit = true;//As this was manualy set we should not override it + } + + @Transient + private transient boolean skipUserAudit = true; } diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBy.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBy.java new file mode 100644 index 0000000000..bd5970eca9 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/CreatedBy.java @@ -0,0 +1,17 @@ +package uk.gov.hmcts.darts.common.entity.base; + +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.time.OffsetDateTime; + +public interface CreatedBy { + UserAccountEntity getCreatedBy(); + + void setCreatedBy(UserAccountEntity userAccount); + + void setCreatedDateTime(OffsetDateTime now); + + boolean isSkipUserAudit(); + + void setSkipUserAudit(boolean value); +} diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/LastModifiedBy.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/LastModifiedBy.java new file mode 100644 index 0000000000..0ca625ccfe --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/LastModifiedBy.java @@ -0,0 +1,17 @@ +package uk.gov.hmcts.darts.common.entity.base; + +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; + +import java.time.OffsetDateTime; + +public interface LastModifiedBy { + UserAccountEntity getLastModifiedBy(); + + void setLastModifiedBy(UserAccountEntity userAccount); + + void setLastModifiedDateTime(OffsetDateTime now); + + boolean isSkipUserAudit(); + + void setSkipUserAudit(boolean value); +} diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedBaseEntity.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedBaseEntity.java index 83a4815041..61918027d0 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedBaseEntity.java +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedBaseEntity.java @@ -2,15 +2,18 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.Transient; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.envers.NotAudited; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.listener.UserAuditListener; import java.time.OffsetDateTime; import javax.validation.constraints.NotNull; @@ -18,7 +21,8 @@ @MappedSuperclass @Getter @Setter -public class MandatoryCreatedBaseEntity { +@EntityListeners(UserAuditListener.class) +public class MandatoryCreatedBaseEntity implements CreatedBy { @NotNull @CreationTimestamp @@ -31,4 +35,12 @@ public class MandatoryCreatedBaseEntity { @JoinColumn(name = "created_by", nullable = false) private UserAccountEntity createdBy; + public void setCreatedBy(UserAccountEntity userAccount) { + this.createdBy = userAccount; + this.skipUserAudit = true;//As this was manualy set we should not override it + } + + @Transient + protected transient boolean skipUserAudit = true; + } \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedModifiedBaseEntity.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedModifiedBaseEntity.java index d4a5aba265..cc61f201c5 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedModifiedBaseEntity.java +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/MandatoryCreatedModifiedBaseEntity.java @@ -2,6 +2,7 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; @@ -11,13 +12,15 @@ import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.envers.NotAudited; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.listener.UserAuditListener; import java.time.OffsetDateTime; @MappedSuperclass @Getter @Setter -public class MandatoryCreatedModifiedBaseEntity extends MandatoryCreatedBaseEntity { +@EntityListeners(UserAuditListener.class) +public class MandatoryCreatedModifiedBaseEntity extends MandatoryCreatedBaseEntity implements LastModifiedBy { @UpdateTimestamp @Column(name = "last_modified_ts", nullable = false) @@ -27,4 +30,10 @@ public class MandatoryCreatedModifiedBaseEntity extends MandatoryCreatedBaseEnti @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @JoinColumn(name = "last_modified_by", nullable = false) private UserAccountEntity lastModifiedBy; + + public void setLastModifiedBy(UserAccountEntity userAccount) { + this.lastModifiedBy = userAccount; + this.skipUserAudit = true;//As this was manualy set we should not override it + } + } diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/base/ModifiedBaseEntity.java b/src/main/java/uk/gov/hmcts/darts/common/entity/base/ModifiedBaseEntity.java index 9d97b92ea9..d4194d8bad 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/entity/base/ModifiedBaseEntity.java +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/base/ModifiedBaseEntity.java @@ -1,21 +1,25 @@ package uk.gov.hmcts.darts.common.entity.base; import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.Transient; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UpdateTimestamp; import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.listener.UserAuditListener; import java.time.OffsetDateTime; @MappedSuperclass @Getter @Setter -public class ModifiedBaseEntity { +@EntityListeners(UserAuditListener.class) +public class ModifiedBaseEntity implements LastModifiedBy { @UpdateTimestamp @Column(name = "last_modified_ts") @@ -24,4 +28,17 @@ public class ModifiedBaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "last_modified_by") private UserAccountEntity lastModifiedBy; + + @Override + public void setLastModifiedDateTime(OffsetDateTime lastModifiedTimestamp) { + this.lastModifiedTimestamp = lastModifiedTimestamp; + } + + public void setLastModifiedBy(UserAccountEntity userAccount) { + this.lastModifiedBy = userAccount; + this.skipUserAudit = true;//As this was manualy set we should not override it + } + + @Transient + private transient boolean skipUserAudit = true; } diff --git a/src/main/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListener.java b/src/main/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListener.java new file mode 100644 index 0000000000..e8873d1508 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListener.java @@ -0,0 +1,104 @@ +package uk.gov.hmcts.darts.common.entity.listener; + +import jakarta.persistence.PostLoad; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.core.context.SecurityContextHolder; +import uk.gov.hmcts.darts.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.base.CreatedBy; +import uk.gov.hmcts.darts.common.entity.base.LastModifiedBy; + +import java.time.Clock; +import java.time.OffsetDateTime; +import java.util.Optional; + +@Slf4j +public class UserAuditListener { + + private final Clock clock; + private final UserIdentity userIdentity; + + + @Autowired + public UserAuditListener(Clock clock, @Lazy UserIdentity userIdentity) { + this.clock = clock; + this.userIdentity = userIdentity; + } + + + @PrePersist + void beforeSave(Object object) { + log.debug("Before save: {}", object.getClass().getSimpleName()); + updateCreatedBy(object); + updateModifiedBy(object); + } + + @PreUpdate + void beforeUpdate(Object object) { + log.debug("Before update: {}", object.getClass().getSimpleName()); + updateModifiedBy(object); + } + + @PostLoad + void postLoad(Object object) { + if (object instanceof CreatedBy entity) { + entity.setSkipUserAudit(false); + } + if (object instanceof LastModifiedBy entity) { + entity.setSkipUserAudit(false); + } + } + + Optional getUserAccount() { + try { + return Optional.ofNullable(userIdentity.getUserAccount()); + } catch (Exception e) { + log.error("Error getting user account", e); + return Optional.empty(); + } + } + + boolean isUserAccountPresent() { + return SecurityContextHolder.getContext().getAuthentication() != null; + } + + void updateCreatedBy(Object object) { + if (object instanceof CreatedBy entity) { + if (entity.isSkipUserAudit() || entity.getCreatedBy() != null) { + log.debug("Skipping audit as isSkipUserAudit is set or createdBy is already set"); + return; + } + Optional userAccountOpt = getUserAccount(); + if (userAccountOpt.isEmpty()) { + log.debug("Before save: {} - Skipping audit as user account not found", object.getClass().getSimpleName()); + return; + } + UserAccountEntity userAccount = userAccountOpt.get(); + entity.setCreatedBy(userAccount); + entity.setCreatedDateTime(OffsetDateTime.now(clock)); + } + } + + + void updateModifiedBy(Object object) { + if (object instanceof LastModifiedBy entity) { + if (entity.isSkipUserAudit()) { + log.debug("Skipping audit as isSkipUserAudit is set"); + return; + } + + Optional userAccountOpt = getUserAccount(); + if (userAccountOpt.isEmpty()) { + log.debug("Before update: {} - Skipping audit as user account not found", object.getClass().getSimpleName()); + return; + } + UserAccountEntity userAccount = userAccountOpt.get(); + entity.setLastModifiedDateTime(OffsetDateTime.now(clock)); + entity.setLastModifiedBy(userAccount); + } + } +} diff --git a/src/main/java/uk/gov/hmcts/darts/common/repository/TransformedMediaRepository.java b/src/main/java/uk/gov/hmcts/darts/common/repository/TransformedMediaRepository.java index c42a6883e1..7a00e38b6e 100644 --- a/src/main/java/uk/gov/hmcts/darts/common/repository/TransformedMediaRepository.java +++ b/src/main/java/uk/gov/hmcts/darts/common/repository/TransformedMediaRepository.java @@ -91,6 +91,4 @@ List findTransformedMedia(Integer mediaId, String requestedBy, OffsetDateTime requestedAtFrom, OffsetDateTime requestedAtTo); - - } \ No newline at end of file diff --git a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java index 0e767c119a..220831dfb5 100644 --- a/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java +++ b/src/test/java/uk/gov/hmcts/darts/audio/service/impl/AudioTransformationServiceImplTest.java @@ -50,6 +50,7 @@ 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.doAnswer; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -177,9 +178,12 @@ void getMediaByHearingIdShouldReturnRepositoryResultsUnmodifiedWhenRepositoryRes } @Test - void saveProcessedDataShouldSaveBlobAndSetStatus() { + void saveProcessedData_shouldSaveBlobAndSetStatus() { final MediaRequestEntity mediaRequestEntity = new MediaRequestEntity(); mediaRequestEntity.setRequestType(DOWNLOAD); + UserAccountEntity userAccount = new UserAccountEntity(); + userAccount.setId(1); + mediaRequestEntity.setCreatedBy(userAccount); BlobClientUploadResponse blobClientUploadResponse = mock(BlobClientUploadResponseImpl.class); UUID blobName = UUID.randomUUID(); @@ -198,9 +202,10 @@ void saveProcessedDataShouldSaveBlobAndSetStatus() { TransformedMediaEntity transformedMediaEntity = new TransformedMediaEntity(); transformedMediaEntity.setId(1); - when(transformedMediaRepository.save( - any() - )).thenReturn(transformedMediaEntity); + doAnswer(invocation -> invocation.getArgument(0)).when(transformedMediaRepository).save(any()); + + when(mockTransientObjectDirectoryEntity.getTransformedMedia()) + .thenReturn(transformedMediaEntity); when(mockTransientObjectDirectoryEntity.getTransformedMedia( )).thenReturn(transformedMediaEntity); @@ -543,7 +548,10 @@ void whenCreateTransformMediaEntityIsCalled_thenFilenameFormatSizeShouldBeSet() MediaRequestEntity mediaRequest = new MediaRequestEntity(); mediaRequest.setRequestType(AudioRequestType.PLAYBACK); - + UserAccountEntity userAccount = new UserAccountEntity(); + userAccount.setId(1); + mediaRequest.setCreatedBy(userAccount); + doAnswer(invocation -> invocation.getArgument(0)).when(transformedMediaRepository).save(any()); TransformedMediaEntity transformedMediaEntity = transformedMediaHelper.createTransformedMediaEntity( mediaRequest, "case1_23_Nov_2023.mp3", @@ -552,6 +560,8 @@ void whenCreateTransformMediaEntityIsCalled_thenFilenameFormatSizeShouldBeSet() BINARY_DATA.getLength() ); + assertEquals(userAccount, transformedMediaEntity.getCreatedBy()); + assertEquals(userAccount, transformedMediaEntity.getLastModifiedBy()); assertEquals(TEST_FILE_NAME, transformedMediaEntity.getOutputFilename()); assertEquals(TEST_EXTENSION, transformedMediaEntity.getOutputFormat().getExtension()); assertEquals(TEST_BINARY_STRING.length(), transformedMediaEntity.getOutputFilesize()); diff --git a/src/test/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListenerTest.java b/src/test/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListenerTest.java new file mode 100644 index 0000000000..4164de9773 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/darts/common/entity/listener/UserAuditListenerTest.java @@ -0,0 +1,145 @@ +package uk.gov.hmcts.darts.common.entity.listener; + +import org.junit.jupiter.api.BeforeEach; +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.authorisation.component.UserIdentity; +import uk.gov.hmcts.darts.common.entity.UserAccountEntity; +import uk.gov.hmcts.darts.common.entity.base.CreatedBy; +import uk.gov.hmcts.darts.common.entity.base.LastModifiedBy; + +import java.time.Clock; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class UserAuditListenerTest { + + //TODO finish testing + private final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); + + @Mock + private UserIdentity userIdentity; + + private UserAuditListener userAuditListener; + + + @BeforeEach + void beforeEach() { + userAuditListener = spy(new UserAuditListener(clock, userIdentity)); + } + + private UserAccountEntity mockUserAccount() { + UserAccountEntity userAccount = mock(UserAccountEntity.class); + when(userIdentity.getUserAccount()).thenReturn(userAccount); + return userAccount; + } + + @Test + void beforeSave_shouldUpdateCreatedByAndModifiedBy() { + doNothing().when(userAuditListener).updateCreatedBy(any()); + doNothing().when(userAuditListener).updateModifiedBy(any()); + + CreatedBy createdBy = mock(CreatedBy.class); + userAuditListener.beforeSave(createdBy); + + verify(userAuditListener).updateCreatedBy(createdBy); + verify(userAuditListener).updateModifiedBy(createdBy); + } + + @Test + void beforeUpdate_shouldUpdateModifiedBy() { + doNothing().when(userAuditListener).updateModifiedBy(any()); + + CreatedBy createdBy = mock(CreatedBy.class); + userAuditListener.beforeUpdate(createdBy); + + verify(userAuditListener, never()).updateCreatedBy(any()); + verify(userAuditListener).updateModifiedBy(createdBy); + } + + + @Test + void getUserAccount_shouldReturnUserAccount_whenUserAccountIsPresent() { + UserAccountEntity mockUserAccount = mockUserAccount(); + + Optional userAccount = userAuditListener.getUserAccount(); + assertThat(userAccount.isPresent()).isTrue(); + assertThat(userAccount.get()).isEqualTo(mockUserAccount); + verify(userIdentity).getUserAccount(); + } + + @Test + void getUserAccount_shouldReturnEmpty_whenUserAccountIsNotPresent() { + Optional userAccount = userAuditListener.getUserAccount(); + assertThat(userAccount.isPresent()).isFalse(); + verify(userIdentity).getUserAccount(); + } + + @Test + void updateCreatedBy_shouldUpdateCreatedBy_whenEntityIsCreatedByAndSkipUserAuditIsFalseAndCreatedByIsNull() { + UserAccountEntity userAccount = mockUserAccount(); + CreatedBy createdBy = mock(CreatedBy.class); + when(createdBy.isSkipUserAudit()).thenReturn(false); + when(createdBy.getCreatedBy()).thenReturn(null); + + userAuditListener.updateCreatedBy(createdBy); + verify(createdBy).setCreatedBy(userAccount); + verify(createdBy).setCreatedDateTime(OffsetDateTime.now(clock)); + } + + @Test + void updateCreatedBy_shouldSkipAudit_whenEntityIsCreatedByAndSkipUserAuditIsTrue() { + CreatedBy createdBy = mock(CreatedBy.class); + when(createdBy.isSkipUserAudit()).thenReturn(true); + + userAuditListener.updateCreatedBy(createdBy); + verify(createdBy, never()).setCreatedBy(any()); + verify(createdBy, never()).setCreatedDateTime(any()); + } + + @Test + void updateCreatedBy_shouldSkipAudit_whenEntityIsCreatedByAndCreatedByIsNotNull() { + CreatedBy createdBy = mock(CreatedBy.class); + when(createdBy.isSkipUserAudit()).thenReturn(false); + when(createdBy.getCreatedBy()).thenReturn(mock(UserAccountEntity.class)); + + userAuditListener.updateCreatedBy(createdBy); + verify(createdBy, never()).setCreatedBy(any()); + verify(createdBy, never()).setCreatedDateTime(any()); + } + + @Test + void updateModifiedBy_shouldUpdateModifiedBy_whenEntityIsLastModifiedByAndSkipUserAuditIsFalse() { + UserAccountEntity userAccount = mockUserAccount(); + LastModifiedBy lastModifiedBy = mock(LastModifiedBy.class); + when(lastModifiedBy.isSkipUserAudit()).thenReturn(false); + + userAuditListener.updateModifiedBy(lastModifiedBy); + verify(lastModifiedBy).setLastModifiedBy(userAccount); + verify(lastModifiedBy).setLastModifiedDateTime(OffsetDateTime.now(clock)); + } + + @Test + void updateModifiedBy_shouldSkipAudit_whenEntityIsLastModifiedByAndSkipUserAuditIsTrue() { + LastModifiedBy lastModifiedBy = mock(LastModifiedBy.class); + when(lastModifiedBy.isSkipUserAudit()).thenReturn(true); + + userAuditListener.updateModifiedBy(lastModifiedBy); + verify(lastModifiedBy, never()).setLastModifiedBy(any()); + verify(lastModifiedBy, never()).setLastModifiedDateTime(any()); + } +}