From 93a4dceaeaefa1ae6f62d74c8c5b874fcdd4c31c Mon Sep 17 00:00:00 2001 From: Anthony Britton Date: Thu, 21 Sep 2023 10:18:17 +0100 Subject: [PATCH] PI-1473 add detail url for probation-case.engagement.created --- .../domain-events-and-delius/build.gradle.kts | 1 + .../justice/digital/hmpps/data/DataLoader.kt | 11 +++- .../hmpps/data/generator/PersonGenerator.kt | 21 ++++++++ .../src/dev/resources/local-public-key.pub | 6 +++ .../__files/hmpps-auth-token-body.json | 10 ++++ .../simulations/mappings/hmpps-auth.json | 13 +++++ .../digital/hmpps/EngagementCreatedTest.kt | 52 +++++++++++++++++++ ...onTest.kt => PublishingIntegrationTest.kt} | 2 +- .../api/engagement/EngagementResource.kt | 17 ++++++ .../delius/person/entity/Person.kt | 49 +++++++++++++++++ .../digital/hmpps/service/PersonService.kt | 33 ++++++++++++ .../src/main/resources/application.yml | 3 ++ 12 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt create mode 100644 projects/domain-events-and-delius/src/dev/resources/local-public-key.pub create mode 100644 projects/domain-events-and-delius/src/dev/resources/simulations/__files/hmpps-auth-token-body.json create mode 100644 projects/domain-events-and-delius/src/dev/resources/simulations/mappings/hmpps-auth.json create mode 100644 projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/EngagementCreatedTest.kt rename projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/{IntegrationTest.kt => PublishingIntegrationTest.kt} (98%) create mode 100644 projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/engagement/EngagementResource.kt create mode 100644 projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/Person.kt create mode 100644 projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt diff --git a/projects/domain-events-and-delius/build.gradle.kts b/projects/domain-events-and-delius/build.gradle.kts index 639524d398..75baff2a70 100644 --- a/projects/domain-events-and-delius/build.gradle.kts +++ b/projects/domain-events-and-delius/build.gradle.kts @@ -6,6 +6,7 @@ dependencies { implementation(project(":libs:audit")) implementation(project(":libs:commons")) implementation(project(":libs:messaging")) + implementation(project(":libs:oauth-server")) implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-data-jpa") diff --git a/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 08c90d5672..bfa7495ef2 100644 --- a/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -1,22 +1,29 @@ package uk.gov.justice.digital.hmpps.data import jakarta.annotation.PostConstruct +import jakarta.persistence.EntityManager import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.ApplicationListener import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.data.generator.UserGenerator import uk.gov.justice.digital.hmpps.user.AuditUserRepository @Component @ConditionalOnProperty("seed.database") class DataLoader( - private val auditUserRepository: AuditUserRepository + private val auditUserRepository: AuditUserRepository, + private val em: EntityManager ) : ApplicationListener { @PostConstruct fun saveAuditUser() { auditUserRepository.save(UserGenerator.AUDIT_USER) } - override fun onApplicationEvent(event: ApplicationReadyEvent) {} + @Transactional + override fun onApplicationEvent(event: ApplicationReadyEvent) { + em.persist(PersonGenerator.ENGAGEMENT_CREATED) + } } diff --git a/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt new file mode 100644 index 0000000000..92a7ca7ce8 --- /dev/null +++ b/projects/domain-events-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -0,0 +1,21 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Person +import java.time.LocalDate + +object PersonGenerator { + val ENGAGEMENT_CREATED = + generate("X789654", "Bernard", "Shepherd", LocalDate.of(1977, 10, 9), pnc = "1977/9999748M") + + fun generate( + crn: String, + forename: String, + surname: String, + dateOfBirth: LocalDate, + secondName: String? = null, + thirdName: String? = null, + pnc: String? = null, + softDeleted: Boolean = false, + id: Long = IdGenerator.getAndIncrement() + ) = Person(crn, pnc, forename, secondName, thirdName, surname, dateOfBirth, softDeleted, id) +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/dev/resources/local-public-key.pub b/projects/domain-events-and-delius/src/dev/resources/local-public-key.pub new file mode 100644 index 0000000000..b19c1e9863 --- /dev/null +++ b/projects/domain-events-and-delius/src/dev/resources/local-public-key.pub @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDju2wS/xXRfjdRI9thM2yJ7xO4 +cy5o8eJ1tljIrqJvKcdsmuflNv7IXGZP4OIQBhALkS3CQxIhBl9gNAtyu2AdYUdn +bSlBS5qLtLg2EoPn2GyGSwRiZCmZcmDsHdn8DX0zNCgZN9i/B/yCL0gXgvHRGEqP +QCtNM3Urqkvn97LVjQIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/dev/resources/simulations/__files/hmpps-auth-token-body.json b/projects/domain-events-and-delius/src/dev/resources/simulations/__files/hmpps-auth-token-body.json new file mode 100644 index 0000000000..a595f9be58 --- /dev/null +++ b/projects/domain-events-and-delius/src/dev/resources/simulations/__files/hmpps-auth-token-body.json @@ -0,0 +1,10 @@ +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJwcm9iYXRpb24taW50ZWdyYXRpb24tZGV2IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInVzZXJfbmFtZSI6InByb2JhdGlvbi1pbnRlZ3JhdGlvbi1kZXYiLCJzY29wZSI6WyJyZWFkIl0sImF1dGhfc291cmNlIjoibm9uZSIsImlzcyI6Imh0dHBzOi8vc2lnbi1pbi1kZXYuaG1wcHMuc2VydmljZS5qdXN0aWNlLmdvdi51ay9hdXRoL2lzc3VlciIsImV4cCI6OTk5OTk5OTk5OSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9WSUVXX1BST0JBVElPTl9DQVNFX0VOR0FHRU1FTlRfQ1JFQVRFRCJdLCJqdGkiOiIyNUR1Um4xLWh5SFpld0xjZEpKeHdWTDAzS1UiLCJjbGllbnRfaWQiOiJwcm9iYXRpb24taW50ZWdyYXRpb24tZGV2IiwiaWF0IjoxNjYzNzU3MzExfQ.w-fJ016upnUJKTPCyGVuIupXRESglhmdD3cvhCyeCU67c8bOdb6gVgpjCMsCxuP-Z5EkIMjLmIe_XvxZQPuLtExgpBbfQ596JMWqco5E6r53Fp8n7BMqR54xhxVoTJRk8em8lrIwGgNnRv9Ee2zhidtxlP2f3GS1G7F48oSTPuE", + "token_type": "bearer", + "expires_in": 9999999999, + "scope": "read write", + "sub": "probation-integration-dev", + "auth_source": "none", + "jti": "fN29JHJy1N7gcYvqe-8B_k5T0mA", + "iss": "https://sign-in-dev.hmpps.service.justice.gov.uk/auth/issuer" +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/dev/resources/simulations/mappings/hmpps-auth.json b/projects/domain-events-and-delius/src/dev/resources/simulations/mappings/hmpps-auth.json new file mode 100644 index 0000000000..8a34b1316e --- /dev/null +++ b/projects/domain-events-and-delius/src/dev/resources/simulations/mappings/hmpps-auth.json @@ -0,0 +1,13 @@ +{ + "request": { + "method": "POST", + "urlPath": "/auth/oauth/token" + }, + "response": { + "headers": { + "Content-Type": "application/json" + }, + "status": 200, + "bodyFileName": "hmpps-auth-token-body.json" + } +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/EngagementCreatedTest.kt b/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/EngagementCreatedTest.kt new file mode 100644 index 0000000000..a1033c0341 --- /dev/null +++ b/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/EngagementCreatedTest.kt @@ -0,0 +1,52 @@ +package uk.gov.justice.digital.hmpps + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.github.tomakehurst.wiremock.WireMockServer +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.security.withOAuth2Token +import uk.gov.justice.digital.hmpps.service.Engagement +import uk.gov.justice.digital.hmpps.service.Identifiers +import uk.gov.justice.digital.hmpps.service.Name + +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +internal class EngagementCreatedTest { + @Autowired + internal lateinit var mockMvc: MockMvc + + @Autowired + internal lateinit var wireMockServer: WireMockServer + + @Autowired + internal lateinit var objectMapper: ObjectMapper + + @Test + fun `engagement details returned from detail url`() { + val person = PersonGenerator.ENGAGEMENT_CREATED + val response = mockMvc + .perform(get("/probation-case.engagement.created/${person.crn}").withOAuth2Token(wireMockServer)) + .andExpect(MockMvcResultMatchers.status().is2xxSuccessful).andReturn().response.contentAsString + + val engagement = objectMapper.readValue(response) + assertThat( + engagement, + equalTo( + Engagement( + Identifiers(person.crn, person.pnc), + Name(person.forename, person.surname, listOf()), + person.dateOfBirth + ) + ) + ) + } +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PublishingIntegrationTest.kt similarity index 98% rename from projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt rename to projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PublishingIntegrationTest.kt index 9b4d6893f5..8be37f6282 100644 --- a/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/domain-events-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/PublishingIntegrationTest.kt @@ -22,7 +22,7 @@ import uk.gov.justice.digital.hmpps.service.enhancement.EnhancedEventType import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @SpringBootTest -internal class IntegrationTest { +internal class PublishingIntegrationTest { @Value("\${messaging.producer.topic}") lateinit var topicName: String diff --git a/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/engagement/EngagementResource.kt b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/engagement/EngagementResource.kt new file mode 100644 index 0000000000..1a3ca05acd --- /dev/null +++ b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/engagement/EngagementResource.kt @@ -0,0 +1,17 @@ +package uk.gov.justice.digital.hmpps.api.engagement + +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import uk.gov.justice.digital.hmpps.service.Engagement +import uk.gov.justice.digital.hmpps.service.PersonService + +@RestController +@RequestMapping +class EngagementResource(private val personService: PersonService) { + @PreAuthorize("hasRole('VIEW_PROBATION_CASE_ENGAGEMENT_CREATED')") + @GetMapping("probation-case.engagement.created/{crn}") + fun getEngagement(@PathVariable crn: String): Engagement = personService.findEngagement(crn) +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/Person.kt b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/Person.kt new file mode 100644 index 0000000000..a623d848bf --- /dev/null +++ b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/Person.kt @@ -0,0 +1,49 @@ +package uk.gov.justice.digital.hmpps.integrations.delius.person.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.Where +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDate + +@Immutable +@Entity +@Table(name = "offender") +@Where(clause = "soft_deleted = 0") +class Person( + + @Column(columnDefinition = "char(7)") + val crn: String, + + @Column(name = "pnc_number", columnDefinition = "char(13)") + val pnc: String?, + + @Column(name = "first_name") + val forename: String, + + @Column(name = "second_name") + val secondName: String?, + + @Column(name = "third_name") + val thirdName: String?, + + @Column(name = "surname") + val surname: String, + + @Column(name = "date_of_birth_date") + val dateOfBirth: LocalDate, + + @Column(columnDefinition = "number") + val softDeleted: Boolean, + + @Id + @Column(name = "offender_id") + val id: Long, +) + +interface PersonRepository : JpaRepository { + fun findByCrn(crn: String): Person? +} \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt new file mode 100644 index 0000000000..8759c914dd --- /dev/null +++ b/projects/domain-events-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -0,0 +1,33 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Person +import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonRepository +import java.time.LocalDate + +@Service +class PersonService(private val personRepository: PersonRepository) { + fun findEngagement(crn: String): Engagement = personRepository.findByCrn(crn)?.asEngagement() + ?: throw NotFoundException("Engagement", "crn", crn) +} + +private fun Person.asEngagement() = Engagement( + Identifiers(crn, pnc), + Name(forename, surname, listOfNotNull(secondName, thirdName)), + dateOfBirth +) + +data class Engagement( + val identifiers: Identifiers, + val name: Name, + val dateOfBirth: LocalDate +) + +data class Identifiers(val crn: String, val pnc: String?) + +data class Name( + val forename: String, + val surname: String, + val otherNames: List +) \ No newline at end of file diff --git a/projects/domain-events-and-delius/src/main/resources/application.yml b/projects/domain-events-and-delius/src/main/resources/application.yml index 64fab77667..7c580fcb86 100644 --- a/projects/domain-events-and-delius/src/main/resources/application.yml +++ b/projects/domain-events-and-delius/src/main/resources/application.yml @@ -16,6 +16,8 @@ spring: global_temporary: create_tables: false drop_tables: false +springdoc.default-produces-media-type: application/json + delius.db.username: DomainEventsAndDelius # Should match value in [deploy/database/access.yml]. @@ -31,6 +33,7 @@ spring.config.activate.on-profile: [ "dev", "integration-test" ] spring: datasource.url: jdbc:h2:file:./dev;MODE=Oracle;DEFAULT_NULL_ORDERING=HIGH;AUTO_SERVER=true;AUTO_SERVER_PORT=9092 jpa.hibernate.ddl-auto: create-drop + security.oauth2.resourceserver.jwt.public-key-location: classpath:local-public-key.pub seed.database: true