From 27e7dfe85f894af770e310cea87197f5c9206025 Mon Sep 17 00:00:00 2001 From: Anthony Britton <105213050+anthony-britton-moj@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:15:17 +0100 Subject: [PATCH] PI-2048 (#3570) * PI-2048 --- .../hmpps/audit/service/AuditableService.kt | 7 +++- .../service/AuditedInteractionService.kt | 28 +++++++------- .../audit/service/AuditableServiceTest.kt | 7 +++- .../service/AuditedInteractionServiceTest.kt | 38 ++++++++++++++++++- .../hmpps/service/ContactServiceTest.kt | 4 +- .../justice/digital/hmpps/data/DataLoader.kt | 1 + .../hmpps/data/generator/UserGenerator.kt | 1 + .../justice/digital/hmpps/IntegrationTest.kt | 7 +++- .../hmpps/service/SearchAuditService.kt | 12 +++--- 9 files changed, 77 insertions(+), 28 deletions(-) diff --git a/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableService.kt b/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableService.kt index 63d74f8996..a6d5688ea7 100644 --- a/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableService.kt +++ b/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableService.kt @@ -8,6 +8,7 @@ abstract class AuditableService(private val auditedInteractionService: AuditedIn protected fun audit( interactionCode: InteractionCode, dateTime: ZonedDateTime = ZonedDateTime.now(), + username: String? = null, params: AuditedInteraction.Parameters = AuditedInteraction.Parameters(), code: (AuditedInteraction.Parameters) -> T ): T { @@ -17,7 +18,8 @@ abstract class AuditableService(private val auditedInteractionService: AuditedIn interactionCode, params, AuditedInteraction.Outcome.SUCCESS, - dateTime + dateTime, + username ) return result } catch (e: Exception) { @@ -25,7 +27,8 @@ abstract class AuditableService(private val auditedInteractionService: AuditedIn interactionCode, params, AuditedInteraction.Outcome.FAIL, - dateTime + dateTime, + username ) throw e } diff --git a/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionService.kt b/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionService.kt index 2f37f2fcc2..4d31aedc81 100644 --- a/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionService.kt +++ b/libs/audit/src/main/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionService.kt @@ -10,12 +10,14 @@ import uk.gov.justice.digital.hmpps.audit.repository.AuditedInteractionRepositor import uk.gov.justice.digital.hmpps.audit.repository.BusinessInteractionRepository import uk.gov.justice.digital.hmpps.audit.repository.getByCode import uk.gov.justice.digital.hmpps.security.ServiceContext +import uk.gov.justice.digital.hmpps.user.AuditUserService import java.time.ZonedDateTime @Service class AuditedInteractionService( private val businessInteractionRepository: BusinessInteractionRepository, - private val auditedInteractionRepository: AuditedInteractionRepository + private val auditedInteractionRepository: AuditedInteractionRepository, + private val auditUserService: AuditUserService ) { @Async @Transactional(propagation = Propagation.REQUIRES_NEW) @@ -23,19 +25,19 @@ class AuditedInteractionService( interactionCode: InteractionCode, params: AuditedInteraction.Parameters, outcome: AuditedInteraction.Outcome, - dateTime: ZonedDateTime + dateTime: ZonedDateTime, + username: String? ) { - ServiceContext.servicePrincipal()!!.let { - val bi = businessInteractionRepository.getByCode(interactionCode.code) - auditedInteractionRepository.save( - AuditedInteraction( - businessInteractionId = bi.id, - userId = it.userId, - dateTime = dateTime, - parameters = params, - outcome = outcome - ) + val bi = businessInteractionRepository.getByCode(interactionCode.code) + auditedInteractionRepository.save( + AuditedInteraction( + businessInteractionId = bi.id, + userId = username?.let { auditUserService.findUser(it) }?.id + ?: ServiceContext.servicePrincipal()!!.userId, + dateTime = dateTime, + parameters = params, + outcome = outcome ) - } + ) } } diff --git a/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableServiceTest.kt b/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableServiceTest.kt index 9772e4ab70..f699c29457 100644 --- a/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableServiceTest.kt +++ b/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditableServiceTest.kt @@ -9,6 +9,7 @@ import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.eq import org.mockito.kotlin.verify import uk.gov.justice.digital.hmpps.audit.BusinessInteractionCode @@ -32,7 +33,8 @@ class AuditableServiceTest { eq(BusinessInteractionCode.TEST_BI_CODE), eq(AuditedInteraction.Parameters(mutableMapOf("field" to "value"))), eq(AuditedInteraction.Outcome.SUCCESS), - any() + any(), + anyOrNull() ) } @@ -46,7 +48,8 @@ class AuditableServiceTest { eq(BusinessInteractionCode.TEST_BI_CODE), eq(AuditedInteraction.Parameters(mutableMapOf("field" to "value"))), eq(AuditedInteraction.Outcome.FAIL), - any() + any(), + anyOrNull() ) } diff --git a/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionServiceTest.kt b/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionServiceTest.kt index 3e018aa36e..ae46c4a28e 100644 --- a/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionServiceTest.kt +++ b/libs/audit/src/test/kotlin/uk/gov/justice/digital/hmpps/audit/service/AuditedInteractionServiceTest.kt @@ -69,7 +69,8 @@ class AuditedInteractionServiceTest { BusinessInteractionCode.TEST_BI_CODE, parameters, AuditedInteraction.Outcome.SUCCESS, - dateTime + dateTime, + null ) val aiCaptor = ArgumentCaptor.forClass(AuditedInteraction::class.java) verify(auditedInteractionRepository, Mockito.times(1)).save(aiCaptor.capture()) @@ -95,11 +96,44 @@ class AuditedInteractionServiceTest { BusinessInteractionCode.TEST_BI_CODE, parameters, AuditedInteraction.Outcome.SUCCESS, - ZonedDateTime.now() + ZonedDateTime.now(), + null ) } } + @Test + fun `create audited interaction with username override`() { + setupUser() + val anotherUser = AuditUser(99, "AnotherUser") + whenever(auditUserService.findUser(anotherUser.username)).thenReturn(anotherUser) + + val bi = BusinessInteraction(1, BusinessInteractionCode.TEST_BI_CODE.code, ZonedDateTime.now()) + whenever(businessInteractionRepository.findByCode(eq(BusinessInteractionCode.TEST_BI_CODE.code), any())) + .thenReturn(bi) + + val parameters = AuditedInteraction.Parameters( + Pair("key", "value") + ) + val dateTime = ZonedDateTime.now() + auditedInteractionService.createAuditedInteraction( + BusinessInteractionCode.TEST_BI_CODE, + parameters, + AuditedInteraction.Outcome.SUCCESS, + dateTime, + anotherUser.username + ) + val aiCaptor = ArgumentCaptor.forClass(AuditedInteraction::class.java) + verify(auditedInteractionRepository, Mockito.times(1)).save(aiCaptor.capture()) + val saved = aiCaptor.value + + assertThat(saved.businessInteractionId, equalTo(1)) + assertThat(saved.outcome, equalTo(AuditedInteraction.Outcome.SUCCESS)) + assertThat(saved.userId, equalTo(anotherUser.id)) + assertThat(saved.parameters, equalTo(parameters)) + assertThat(saved.dateTime, equalTo(dateTime)) + } + @Test fun `test audit interaction class`() { val dateTime = ZonedDateTime.now() diff --git a/projects/cas2-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ContactServiceTest.kt b/projects/cas2-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ContactServiceTest.kt index 959f38b11f..3bbb44b85f 100644 --- a/projects/cas2-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ContactServiceTest.kt +++ b/projects/cas2-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ContactServiceTest.kt @@ -92,7 +92,7 @@ class ContactServiceTest { assertThat(it.notes, equalTo("Some notes")) assertThat(it.externalReference, equalTo("urn")) }) - verify(auditedInteractionService).createAuditedInteraction(eq(ADD_CONTACT), any(), any(), any()) + verify(auditedInteractionService).createAuditedInteraction(eq(ADD_CONTACT), any(), any(), any(), anyOrNull()) } @Test @@ -102,7 +102,7 @@ class ContactServiceTest { createContact() verify(contactRepository, never()).save(any()) - verify(auditedInteractionService, never()).createAuditedInteraction(any(), any(), any(), any()) + verify(auditedInteractionService, never()).createAuditedInteraction(any(), any(), any(), any(), anyOrNull()) verify(telemetryService).trackEvent("ContactAlreadyExists", mapOf("urn" to "urn"), mapOf()) } diff --git a/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index a5f403d1a0..ab2190214d 100644 --- a/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -26,6 +26,7 @@ class DataLoader( } override fun onApplicationEvent(are: ApplicationReadyEvent) { + auditUserRepository.save(UserGenerator.SEARCH_USER) BusinessInteractionCode.entries.forEach { bir.save( BusinessInteraction( diff --git a/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt b/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt index 56c08d3493..751570d5ef 100644 --- a/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt +++ b/projects/probation-search-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt @@ -4,4 +4,5 @@ import uk.gov.justice.digital.hmpps.user.AuditUser object UserGenerator { val AUDIT_USER = AuditUser(IdGenerator.getAndIncrement(), "ProbationSearchAndDelius") + val SEARCH_USER = AuditUser(IdGenerator.getAndIncrement(), "SearchUser") } diff --git a/projects/probation-search-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/probation-search-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 790afb8e37..168d399b25 100644 --- a/projects/probation-search-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/probation-search-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -17,6 +17,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status import uk.gov.justice.digital.hmpps.audit.entity.AuditedInteraction import uk.gov.justice.digital.hmpps.audit.repository.AuditedInteractionRepository +import uk.gov.justice.digital.hmpps.data.generator.UserGenerator import uk.gov.justice.digital.hmpps.service.ContactSearchAuditRequest import uk.gov.justice.digital.hmpps.service.ContactSearchRequest import uk.gov.justice.digital.hmpps.service.PageRequest @@ -54,6 +55,7 @@ internal class IntegrationTest { .withJson( ContactSearchAuditRequest( ContactSearchRequest(crn, query, true), + "SearchUser", PageRequest(page, pageSize, sort, direction), dateTime ) @@ -64,13 +66,14 @@ internal class IntegrationTest { verify(air, timeout(2000)).save(audit.capture()) val saved = audit.firstValue + assertThat(saved.userId, equalTo(UserGenerator.SEARCH_USER.id)) assertThat(saved.parameters["crn"], equalTo(crn)) assertThat(saved.parameters["query"], equalTo(query)) assertThat(saved.parameters["matchAllTerms"], equalTo(true)) assertThat(saved.parameters["page"], equalTo(page)) assertThat(saved.parameters["pageSize"], equalTo(pageSize)) - assertThat(saved.parameters["sort"], equalTo(sort)) - assertThat(saved.parameters["direction"], equalTo(direction)) + assertThat(saved.parameters["sortedBy"], equalTo(sort)) + assertThat(saved.parameters["sortDirection"], equalTo(direction)) assertThat(saved.dateTime, isCloseTo(dateTime)) } } diff --git a/projects/probation-search-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/SearchAuditService.kt b/projects/probation-search-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/SearchAuditService.kt index 1f443a3b1d..c3eb2d5ae4 100644 --- a/projects/probation-search-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/SearchAuditService.kt +++ b/projects/probation-search-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/SearchAuditService.kt @@ -7,10 +7,11 @@ import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractio import java.time.ZonedDateTime @Service -class SearchAuditService(auditedInteractionService: AuditedInteractionService) : - AuditableService(auditedInteractionService) { +class SearchAuditService( + auditedInteractionService: AuditedInteractionService +) : AuditableService(auditedInteractionService) { fun auditContactSearch(auditRequest: ContactSearchAuditRequest) = - audit(BusinessInteractionCode.SEARCH_CONTACTS, auditRequest.dateTime) { audit -> + audit(BusinessInteractionCode.SEARCH_CONTACTS, auditRequest.dateTime, auditRequest.username) { audit -> with(auditRequest.search) { audit["crn"] = crn query?.also { audit["query"] = it } @@ -19,14 +20,15 @@ class SearchAuditService(auditedInteractionService: AuditedInteractionService) : with(auditRequest.pagination) { audit["page"] = page audit["pageSize"] = pageSize - sort?.also { audit["sort"] = it } - direction?.also { audit["direction"] = it } + sort?.also { audit["sortedBy"] = it } + direction?.also { audit["sortDirection"] = it } } } } data class ContactSearchAuditRequest( val search: ContactSearchRequest, + val username: String, val pagination: PageRequest, val dateTime: ZonedDateTime )