From 30ab577805bf990bbaa229358f57fbc0166a9b64 Mon Sep 17 00:00:00 2001 From: gregkhawkins <148795810+gregkhawkins@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:53:42 +0000 Subject: [PATCH 1/6] APS-1482 - changes to offence id generation and offences data setup (#4444) --- .../hmpps/data/ProbationCaseDataLoader.kt | 40 +++++++++++++++---- .../hmpps/ProbationCaseIntegrationTest.kt | 6 +++ .../delius/person/offence/entity/Offence.kt | 4 +- .../justice/digital/hmpps/model/CaseDetail.kt | 2 +- .../digital/hmpps/service/CaseService.kt | 3 +- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/ProbationCaseDataLoader.kt b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/ProbationCaseDataLoader.kt index 2194d12f44..e3fedcc622 100644 --- a/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/ProbationCaseDataLoader.kt +++ b/projects/approved-premises-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/ProbationCaseDataLoader.kt @@ -101,14 +101,30 @@ class ProbationCaseDataLoader( ) ) - listOf( + generateEventAndAddOffences( ProbationCaseGenerator.CASE_COMPLEX, + eventId = 100001L, + mainOffence = Pair(200001L, LocalDate.parse("2024-10-11")), + additionalOffence = Pair(300001L, LocalDate.parse("2024-10-21")) + ) + generateEventAndAddOffences( ProbationCaseGenerator.CASE_X320741, + eventId = 100002L, + mainOffence = Pair(200002L, LocalDate.parse("2024-10-12")), + additionalOffence = Pair(300002L, LocalDate.parse("2024-10-22")) + ) + generateEventAndAddOffences( ProbationCaseGenerator.CASE_LAO_RESTRICTED, + eventId = 100003L, + mainOffence = Pair(200003L, LocalDate.parse("2024-10-13")), + additionalOffence = Pair(300003L, LocalDate.parse("2024-10-23")) + ) + generateEventAndAddOffences( ProbationCaseGenerator.CASE_LAO_EXCLUSION, - ).forEach { - generateEventAndAddOffences(probationCase = it) - } + eventId = 100004L, + mainOffence = Pair(200004L, LocalDate.parse("2024-10-14")), + additionalOffence = Pair(300004L, LocalDate.parse("2024-10-24")) + ) personalCircumstanceTypeRepository.saveAll(PersonalCircumstanceGenerator.PC_TYPES) personalCircumstanceSubTypeRepository.saveAll(PersonalCircumstanceGenerator.PC_SUB_TYPES) @@ -125,17 +141,24 @@ class ProbationCaseDataLoader( exclusionRepository.save(LimitedAccessGenerator.generateExclusion(EXCLUDED_CASE.toLimitedAccessPerson())) } - private fun generateEventAndAddOffences(probationCase: ProbationCase) { + private fun generateEventAndAddOffences( + probationCase: ProbationCase, + eventId: Long, + mainOffence: Pair, + additionalOffence: Pair, + ) { val event = PersonGenerator.generateEvent( "1", - probationCase.id + probationCase.id, + id = eventId ).apply(eventRepository::save) mainOffenceRepository.save( OffenceGenerator.generateMainOffence( event, OffenceGenerator.OFFENCE_ONE, - LocalDate.now().minusDays(7) + id = mainOffence.first, + date = mainOffence.second ) ) @@ -143,7 +166,8 @@ class ProbationCaseDataLoader( OffenceGenerator.generateAdditionalOffence( event, OffenceGenerator.OFFENCE_TWO, - LocalDate.now().minusDays(5) + id = additionalOffence.first, + date = additionalOffence.second ) ) } diff --git a/projects/approved-premises-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ProbationCaseIntegrationTest.kt b/projects/approved-premises-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ProbationCaseIntegrationTest.kt index ffa54129ac..23e75f272f 100644 --- a/projects/approved-premises-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ProbationCaseIntegrationTest.kt +++ b/projects/approved-premises-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ProbationCaseIntegrationTest.kt @@ -70,9 +70,15 @@ class ProbationCaseIntegrationTest { assertThat(detail.mappaDetail?.level, equalTo(2)) assertThat(detail.registrations.map { it.description }, equalTo(listOf("Description of ARSO"))) val mainOffence = detail.offences.first { it.main } + assertThat(mainOffence.id, equalTo("M200001")) assertThat(mainOffence.description, equalTo("Offence One")) + assertThat(mainOffence.date, equalTo(LocalDate.parse("2024-10-11"))) + assertThat(mainOffence.eventId, equalTo(100001L)) val otherOffence = detail.offences.first { !it.main } + assertThat(otherOffence.id, equalTo("A300001")) assertThat(otherOffence.description, equalTo("Offence Two")) + assertThat(otherOffence.date, equalTo(LocalDate.parse("2024-10-21"))) + assertThat(otherOffence.eventId, equalTo(100001L)) assertThat(detail.careLeaver, equalTo(false)) assertThat(detail.veteran, equalTo(true)) } diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/offence/entity/Offence.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/offence/entity/Offence.kt index 951cdae8f7..97d91a0220 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/offence/entity/Offence.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/offence/entity/Offence.kt @@ -88,7 +88,7 @@ interface MainOffenceRepository : JpaRepository { @Query( """ select - mo.offence.id as id, + mo.id as id, mo.offence.code as code, mo.offence.description as description, mo.date as date, @@ -99,7 +99,7 @@ interface MainOffenceRepository : JpaRepository { where mo.event.personId = :personId and mo.event.active = true union all select - ao.offence.id, + ao.id, ao.offence.code, ao.offence.description, ao.date, diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/CaseDetail.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/CaseDetail.kt index b7359827c0..0cf9687caa 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/CaseDetail.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/CaseDetail.kt @@ -59,7 +59,7 @@ data class MappaDetail( ) data class Offence( - val id: Long, + val id: String, val code: String, val description: String, val date: LocalDate?, diff --git a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/CaseService.kt b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/CaseService.kt index 49cc6a0f32..8585a9cd9c 100644 --- a/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/CaseService.kt +++ b/projects/approved-premises-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/CaseService.kt @@ -87,7 +87,8 @@ fun CommunityManager.team() = Team( team.endDate ) -fun CaseOffence.asOffence() = Offence(id, code, description, date, main, eventId, eventNumber) +fun CaseOffence.asOffence() = + Offence(id = if (main) "M$id" else "A$id", code, description, date, main, eventId, eventNumber) fun Registration.asRegistration() = uk.gov.justice.digital.hmpps.model.Registration(type.code, type.description, date) fun Registration.asMappa() = MappaDetail( From 85aacfeed26a66e7799d42e1229c7f8d16ec0e3c Mon Sep 17 00:00:00 2001 From: Marcus Aspin Date: Wed, 20 Nov 2024 14:21:07 +0000 Subject: [PATCH 2/6] PI-2653 Ignore temporary absence movements with no toAgency/fromAgency (#4446) --- .../kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index 2ccba192f4..eff2585ee6 100644 --- a/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/prison-custody-status-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -168,7 +168,7 @@ fun Booking.prisonerMovement(movement: Movement): PrisonerMovement { Booking.InOutStatus.IN -> PrisonerMovement.Received( personReference, movement.fromAgency, - movement.toAgency!!, + movement.toAgency ?: throw IgnorableMessageException("TemporaryAbsenceNoAgency"), PrisonerMovement.Type.valueOf(reason), movement.movementReason, dateTime @@ -176,7 +176,7 @@ fun Booking.prisonerMovement(movement: Movement): PrisonerMovement { Booking.InOutStatus.OUT -> PrisonerMovement.Released( personReference, - movement.fromAgency!!, + movement.fromAgency ?: throw IgnorableMessageException("TemporaryAbsenceNoAgency"), movement.toAgency, PrisonerMovement.Type.valueOf(reason), movement.movementReason, From da84e3fd8474bafbe769adabe45192cef0b390f4 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:52:55 +0000 Subject: [PATCH 3/6] PI-2564 Create initial project for assess-for-early-release-and-delius (#4447) * PI-2564 Create initial project for assess-for-early-release-and-delius * Update access.yml --------- Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com> Co-authored-by: Marcus Aspin --- .github/workflows/access.yml | 1 + .github/workflows/build.yml | 1 + .github/workflows/deploy.yml | 1 + .github/workflows/service-catalogue.yml | 1 + ...ssess-for-early-release-and-delius.run.xml | 29 +++ doc/tech-docs/source/services.html.md.erb | 1 + .../.trivyignore | 0 .../README.md | 3 + .../applicationinsights.json | 62 ++++++ .../build.gradle.kts | 36 ++++ .../deploy/Chart.yaml | 13 ++ .../deploy/database/access.yml | 9 + .../deploy/values-dev.yml | 17 ++ .../deploy/values-preprod.yml | 16 ++ .../deploy/values-prod.yml | 10 + .../deploy/values.yaml | 23 +++ .../settings.gradle.kts | 1 + .../justice/digital/hmpps/data/DataLoader.kt | 25 +++ .../hmpps/data/generator/UserGenerator.kt | 7 + .../justice/digital/hmpps/IntegrationTest.kt | 30 +++ .../uk/gov/justice/digital/hmpps/App.kt | 11 ++ .../digital/hmpps/controller/ApiController.kt | 17 ++ .../src/main/resources/application.yml | 73 ++++++++ .../tech-docs/.gitignore | 20 ++ .../tech-docs/.template_version | 3 + .../tech-docs/Gemfile | 12 ++ .../tech-docs/Gemfile.lock | 177 ++++++++++++++++++ .../tech-docs/config.rb | 8 + .../tech-docs/config/tech-docs.yml | 44 +++++ .../source/api-reference.html.md.erb | 19 ++ .../tech-docs/source/index.html.md.erb | 7 + .../source/javascripts/application.js | 1 + .../source/stylesheets/print.css.scss | 3 + .../source/stylesheets/screen-old-ie.css.scss | 4 + .../source/stylesheets/screen.css.scss | 1 + settings.gradle.kts | 1 + 36 files changed, 687 insertions(+) create mode 100644 .idea/runConfigurations/assess-for-early-release-and-delius.run.xml create mode 100644 projects/assess-for-early-release-and-delius/.trivyignore create mode 100644 projects/assess-for-early-release-and-delius/README.md create mode 100644 projects/assess-for-early-release-and-delius/applicationinsights.json create mode 100644 projects/assess-for-early-release-and-delius/build.gradle.kts create mode 100644 projects/assess-for-early-release-and-delius/deploy/Chart.yaml create mode 100644 projects/assess-for-early-release-and-delius/deploy/database/access.yml create mode 100644 projects/assess-for-early-release-and-delius/deploy/values-dev.yml create mode 100644 projects/assess-for-early-release-and-delius/deploy/values-preprod.yml create mode 100644 projects/assess-for-early-release-and-delius/deploy/values-prod.yml create mode 100644 projects/assess-for-early-release-and-delius/deploy/values.yaml create mode 100644 projects/assess-for-early-release-and-delius/settings.gradle.kts create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt create mode 100644 projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/resources/application.yml create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/.gitignore create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/.template_version create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/Gemfile create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/Gemfile.lock create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/config.rb create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/config/tech-docs.yml create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/api-reference.html.md.erb create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/index.html.md.erb create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/javascripts/application.js create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/print.css.scss create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen-old-ie.css.scss create mode 100644 projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen.css.scss diff --git a/.github/workflows/access.yml b/.github/workflows/access.yml index 6f53002e2c..6e6b41dcd4 100644 --- a/.github/workflows/access.yml +++ b/.github/workflows/access.yml @@ -58,6 +58,7 @@ on: - '["ims-and-delius"]' - '["appointment-reminders-and-delius"]' - '["justice-email-and-delius"]' + - '["assess-for-early-release-and-delius"]' # ^ add new projects here # GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments # See https://github.com/community/community/discussions/11795 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7afa312374..91ab71ace3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,6 +85,7 @@ jobs: - ims-and-delius - appointment-reminders-and-delius - justice-email-and-delius + - assess-for-early-release-and-delius # ^ add new projects here # GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments # See https://github.com/community/community/discussions/11795 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b857195496..d05a39a339 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -73,6 +73,7 @@ on: - '["ims-and-delius"]' - '["appointment-reminders-and-delius"]' - '["justice-email-and-delius"]' + - '["assess-for-early-release-and-delius"]' # ^ add new projects here # GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments # See https://github.com/community/community/discussions/11795 diff --git a/.github/workflows/service-catalogue.yml b/.github/workflows/service-catalogue.yml index 8250e66ce2..f99dd0b0d5 100644 --- a/.github/workflows/service-catalogue.yml +++ b/.github/workflows/service-catalogue.yml @@ -58,6 +58,7 @@ on: - '["ims-and-delius"]' - '["appointment-reminders-and-delius"]' - '["justice-email-and-delius"]' + - '["assess-for-early-release-and-delius"]' # ^ add new projects here # GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments # See https://github.com/community/community/discussions/11795 diff --git a/.idea/runConfigurations/assess-for-early-release-and-delius.run.xml b/.idea/runConfigurations/assess-for-early-release-and-delius.run.xml new file mode 100644 index 0000000000..80e0aa569f --- /dev/null +++ b/.idea/runConfigurations/assess-for-early-release-and-delius.run.xml @@ -0,0 +1,29 @@ + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/doc/tech-docs/source/services.html.md.erb b/doc/tech-docs/source/services.html.md.erb index 8225b8c9e8..cfee61c3ff 100644 --- a/doc/tech-docs/source/services.html.md.erb +++ b/doc/tech-docs/source/services.html.md.erb @@ -85,4 +85,5 @@ weight: 20 * [Ims And Delius](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/ims-and-delius) * [Appointment Reminders And Delius](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/appointment-reminders-and-delius) * [Justice Email And Delius](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/justice-email-and-delius) +* [Assess For Early Release And Delius](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/assess-for-early-release-and-delius)
  • ^ add new projects here
  • diff --git a/projects/assess-for-early-release-and-delius/.trivyignore b/projects/assess-for-early-release-and-delius/.trivyignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/assess-for-early-release-and-delius/README.md b/projects/assess-for-early-release-and-delius/README.md new file mode 100644 index 0000000000..e91a03d980 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/README.md @@ -0,0 +1,3 @@ +# assess-for-early-release-and-delius + +// TODO Describe the service \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/applicationinsights.json b/projects/assess-for-early-release-and-delius/applicationinsights.json new file mode 100644 index 0000000000..012edad194 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/applicationinsights.json @@ -0,0 +1,62 @@ +{ + "role": { + "name": "assess-for-early-release-and-delius" + }, + "customDimensions": { + "service.version": "${VERSION}", + "service.team": "probation-integration" + }, + "instrumentation": { + "logging": { + "level": "DEBUG" + }, + "springScheduling": { + "enabled": false + } + }, + "selfDiagnostics": { + "destination": "console" + }, + "sampling": { + "percentage": 100 + }, + "preview": { + "sampling": { + "overrides": [ + { + "telemetryType": "request", + "attributes": [ + { + "key": "http.url", + "value": "https?://[^/]+/health/?.*", + "matchType": "regexp" + } + ], + "percentage": 0 + }, + { + "telemetryType": "request", + "attributes": [ + { + "key": "http.url", + "value": "https?://[^/]+/info/?.*", + "matchType": "regexp" + } + ], + "percentage": 0 + }, + { + "telemetryType": "dependency", + "attributes": [ + { + "key": "db.operation", + "value": "SELECT", + "matchType": "strict" + } + ], + "percentage": 10 + } + ] + } + } +} \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/build.gradle.kts b/projects/assess-for-early-release-and-delius/build.gradle.kts new file mode 100644 index 0000000000..a089a2f210 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/build.gradle.kts @@ -0,0 +1,36 @@ +import uk.gov.justice.digital.hmpps.extensions.ClassPathExtension + +apply(plugin = "com.google.cloud.tools.jib") + +dependencies { + implementation(project(":libs:audit")) + implementation(project(":libs:commons")) + implementation(project(":libs:oauth-server")) + + implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-security") + implementation("org.springframework.boot:spring-boot-starter-validation") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation(libs.springdoc) + + dev(project(":libs:dev-tools")) + dev("com.h2database:h2") + dev("org.testcontainers:oracle-xe") + + runtimeOnly("com.oracle.database.jdbc:ojdbc11") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation(libs.bundles.mockito) +} + +configure { + jacocoExclusions = listOf( + "**/config/**", + "**/entity/**", + "**/AppKt.class" + ) +} diff --git a/projects/assess-for-early-release-and-delius/deploy/Chart.yaml b/projects/assess-for-early-release-and-delius/deploy/Chart.yaml new file mode 100644 index 0000000000..1c5c964515 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +appVersion: '1.0' +description: A Helm chart for Kubernetes +name: assess-for-early-release-and-delius +version: 1.0.0 + +dependencies: + - name: generic-service + version: "3.2" + repository: https://ministryofjustice.github.io/hmpps-helm-charts + - name: generic-prometheus-alerts + version: "1.4" + repository: https://ministryofjustice.github.io/hmpps-helm-charts \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/deploy/database/access.yml b/projects/assess-for-early-release-and-delius/deploy/database/access.yml new file mode 100644 index 0000000000..e8bd4437b7 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/database/access.yml @@ -0,0 +1,9 @@ +database: + access: + username_key: /assess-for-early-release-and-delius/db-username + password_key: /assess-for-early-release-and-delius/db-password + + audit: + username: AssessForEarlyReleaseAndDelius + forename: Assess for Early Release + surname: Service diff --git a/projects/assess-for-early-release-and-delius/deploy/values-dev.yml b/projects/assess-for-early-release-and-delius/deploy/values-dev.yml new file mode 100644 index 0000000000..41baa373a1 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/values-dev.yml @@ -0,0 +1,17 @@ +enabled: false # TODO set this to true when you're ready to deploy your service + +generic-service: + ingress: + host: assess-for-early-release-and-delius-dev.hmpps.service.justice.gov.uk + + scheduledDowntime: + enabled: true + + env: + SENTRY_ENVIRONMENT: dev + LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/issuer + +generic-prometheus-alerts: + businessHoursOnly: true diff --git a/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml b/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml new file mode 100644 index 0000000000..23a555dccd --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml @@ -0,0 +1,16 @@ +enabled: false # TODO set this to true when you're ready to deploy your service + +generic-service: + ingress: + host: assess-for-early-release-and-delius-preprod.hmpps.service.justice.gov.uk + + scheduledDowntime: + enabled: true + + env: + SENTRY_ENVIRONMENT: preprod + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/issuer + +generic-prometheus-alerts: + businessHoursOnly: true \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/deploy/values-prod.yml b/projects/assess-for-early-release-and-delius/deploy/values-prod.yml new file mode 100644 index 0000000000..a26f2ca45b --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/values-prod.yml @@ -0,0 +1,10 @@ +enabled: false # TODO set this to true when you're ready to deploy your service + +generic-service: + ingress: + host: assess-for-early-release-and-delius.hmpps.service.justice.gov.uk + + env: + SENTRY_ENVIRONMENT: prod + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/issuer diff --git a/projects/assess-for-early-release-and-delius/deploy/values.yaml b/projects/assess-for-early-release-and-delius/deploy/values.yaml new file mode 100644 index 0000000000..9170a7faa4 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/deploy/values.yaml @@ -0,0 +1,23 @@ +# Common values +generic-service: + productId: HMPPS518 + nameOverride: assess-for-early-release-and-delius + + image: + repository: ghcr.io/ministryofjustice/hmpps-probation-integration-services/assess-for-early-release-and-delius + + ingress: + tlsSecretName: assess-for-early-release-and-delius-cert + + namespace_secrets: + common: + SPRING_DATASOURCE_URL: DB_URL + assess-for-early-release-and-delius-database: + SPRING_DATASOURCE_USERNAME: DB_USERNAME + SPRING_DATASOURCE_PASSWORD: DB_PASSWORD + assess-for-early-release-and-delius-sentry: + SENTRY_DSN: SENTRY_DSN + +generic-prometheus-alerts: + targetApplication: assess-for-early-release-and-delius + diff --git a/projects/assess-for-early-release-and-delius/settings.gradle.kts b/projects/assess-for-early-release-and-delius/settings.gradle.kts new file mode 100644 index 0000000000..54c13653a1 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "assess-for-early-release-and-delius" diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt new file mode 100644 index 0000000000..f6ea94c9a7 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -0,0 +1,25 @@ +package uk.gov.justice.digital.hmpps.data + +import jakarta.annotation.PostConstruct +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 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 +) : ApplicationListener { + + @PostConstruct + fun saveAuditUser() { + auditUserRepository.save(UserGenerator.AUDIT_USER) + } + + override fun onApplicationEvent(are: ApplicationReadyEvent) { + // Perform dev/test database setup here, using JPA repositories and generator classes... + } +} diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt new file mode 100644 index 0000000000..63e88c7b6c --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/UserGenerator.kt @@ -0,0 +1,7 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.user.AuditUser + +object UserGenerator { + val AUDIT_USER = AuditUser(IdGenerator.getAndIncrement(), "AssessForEarlyReleaseAndDelius") +} diff --git a/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt new file mode 100644 index 0000000000..d9006c74c5 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps + +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.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken +import uk.gov.justice.digital.hmpps.telemetry.TelemetryService + +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = RANDOM_PORT) +internal class IntegrationTest { + @Autowired + lateinit var mockMvc: MockMvc + + @MockBean + lateinit var telemetryService: TelemetryService + + @Test + fun `API call retuns a success response`() { + mockMvc + .perform(get("/example/123").withToken()) + .andExpect(status().is2xxSuccessful) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt new file mode 100644 index 0000000000..c7faac5b26 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt @@ -0,0 +1,11 @@ +package uk.gov.justice.digital.hmpps + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class App + +fun main(args: Array) { + runApplication(*args) +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt new file mode 100644 index 0000000000..6e4f24c46f --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt @@ -0,0 +1,17 @@ +package uk.gov.justice.digital.hmpps.controller + +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.RestController + +@RestController +class ApiController { + @PreAuthorize("hasRole('EXAMPLE')") + @GetMapping(value = ["/example/{inputId}"]) + fun handle( + @PathVariable("inputId") inputId: String + ) { + // TODO Not yet implemented + } +} diff --git a/projects/assess-for-early-release-and-delius/src/main/resources/application.yml b/projects/assess-for-early-release-and-delius/src/main/resources/application.yml new file mode 100644 index 0000000000..18f07d6fe3 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/resources/application.yml @@ -0,0 +1,73 @@ +# Default config +server.shutdown: graceful +spring: + jackson: + default-property-inclusion: non_null + jpa: + hibernate.ddl-auto: validate + database-platform: org.hibernate.dialect.OracleDialect + properties: + hibernate: + timezone.default_storage: NORMALIZE + query.mutation_strategy: org.hibernate.query.sqm.mutation.internal.inline.InlineMutationStrategy + query.mutation_strategy.persistent: + create_tables: false + drop_tables: false + query.mutation_strategy.global_temporary: + create_tables: false + drop_tables: false + threads.virtual.enabled: true + +oauth2.roles: + - EXAMPLE + +springdoc.default-produces-media-type: application/json + +delius.db.username: AssessForEarlyReleaseAndDelius # Should match value in [deploy/database/access.yml]. + +management: + endpoints.web: + base-path: / + exposure.include: [ "health", "info" ] + endpoint.health.show-details: always + +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + +--- +# Shared dev/test config +spring.config.activate.on-profile: [ "dev", "integration-test" ] +server.shutdown: immediate + +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 + +seed.database: true +wiremock.enabled: true +context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockInitialiser + +logging.level: + uk.gov.justice.digital.hmpps: DEBUG + org.hibernate.tool.schema: ERROR + org.apache.activemq: WARN + +--- +spring.config.activate.on-profile: integration-test +spring.datasource.url: jdbc:h2:mem:./test;MODE=Oracle;DEFAULT_NULL_ORDERING=HIGH + +--- +spring.config.activate.on-profile: oracle +spring: + datasource.url: 'jdbc:tc:oracle:slim-faststart:///XEPDB1' + jpa.hibernate.ddl-auto: create + +--- +spring.config.activate.on-profile: delius-db +spring: + datasource: + url: 'jdbc:oracle:thin:@//localhost:1521/XEPDB1' + username: delius_pool + password: NDelius1 + jpa.hibernate.ddl-auto: validate +seed.database: false +delius.db.username: NationalUser diff --git a/projects/assess-for-early-release-and-delius/tech-docs/.gitignore b/projects/assess-for-early-release-and-delius/tech-docs/.gitignore new file mode 100644 index 0000000000..80d5de85a7 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/.gitignore @@ -0,0 +1,20 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +# Ignore bundler config +/.bundle + +# Ignore the build directory +/build + +# Ignore cache +/.sass-cache +/.cache + +# Ignore .DS_store file +.DS_Store + +Staticfile.auth diff --git a/projects/assess-for-early-release-and-delius/tech-docs/.template_version b/projects/assess-for-early-release-and-delius/tech-docs/.template_version new file mode 100644 index 0000000000..57ff8862e1 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/.template_version @@ -0,0 +1,3 @@ +--- +:remote: https://github.com/alphagov/tech-docs-template.git +:revision: b37e894 \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/tech-docs/Gemfile b/projects/assess-for-early-release-and-delius/tech-docs/Gemfile new file mode 100644 index 0000000000..afef363c09 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/Gemfile @@ -0,0 +1,12 @@ +# If you do not have OpenSSL installed, change +# the following line to use 'http://' +source 'https://rubygems.org' + +# For faster file watcher updates on Windows: +gem 'wdm', '~> 0.1.0', platforms: [:mswin, :mingw, :x64_mingw] + +# Windows does not come with time zone data +gem 'tzinfo-data', platforms: [:mswin, :mingw, :x64_mingw, :jruby] + +# Include the tech docs gem +gem 'govuk_tech_docs' diff --git a/projects/assess-for-early-release-and-delius/tech-docs/Gemfile.lock b/projects/assess-for-early-release-and-delius/tech-docs/Gemfile.lock new file mode 100644 index 0000000000..9fdb19f88e --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.0.7.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.4) + public_suffix (>= 2.0.2, < 6.0) + autoprefixer-rails (10.4.13.0) + execjs (~> 2) + backports (3.24.1) + chronic (0.10.2) + chunky_png (1.4.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + commonmarker (0.23.10) + compass (1.0.3) + chunky_png (~> 1.2) + compass-core (~> 1.0.2) + compass-import-once (~> 1.0.5) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + sass (>= 3.3.13, < 3.5) + compass-core (1.0.3) + multi_json (~> 1.0) + sass (>= 3.3.0, < 3.5) + compass-import-once (1.0.5) + sass (>= 3.2, < 3.5) + concurrent-ruby (1.2.2) + contracts (0.17) + dotenv (2.8.1) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + erubis (2.7.0) + eventmachine (1.2.7) + execjs (2.8.1) + fast_blank (1.0.1) + fastimage (2.2.6) + ffi (1.15.5) + govuk_tech_docs (3.3.1) + autoprefixer-rails (~> 10.2) + chronic (~> 0.10.2) + middleman (~> 4.0) + middleman-autoprefixer (~> 2.10.0) + middleman-compass (>= 4.0.0) + middleman-livereload + middleman-search-gds + middleman-sprockets (~> 4.0.0) + middleman-syntax (~> 3.2.0) + nokogiri + openapi3_parser (~> 0.9.0) + redcarpet (~> 3.5.1) + haml (5.2.2) + temple (>= 0.8.0) + tilt + hamster (3.0.0) + concurrent-ruby (~> 1.0) + hashie (3.6.0) + http_parser.rb (0.8.0) + i18n (1.6.0) + concurrent-ruby (~> 1.0) + kramdown (2.4.0) + rexml + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + memoist (0.16.2) + middleman (4.4.3) + coffee-script (~> 2.2) + haml (>= 4.0.5, < 6.0) + kramdown (>= 2.3.0) + middleman-cli (= 4.4.3) + middleman-core (= 4.4.3) + middleman-autoprefixer (2.10.0) + autoprefixer-rails (>= 9.1.4) + middleman-core (>= 3.3.3) + middleman-cli (4.4.3) + thor (>= 0.17.0, < 2.0) + middleman-compass (4.0.1) + compass (>= 1.0.0, < 2.0.0) + middleman-core (>= 4.0.0) + middleman-core (4.4.3) + activesupport (>= 6.1, < 7.1) + addressable (~> 2.4) + backports (~> 3.6) + bundler (~> 2.0) + contracts (~> 0.13) + dotenv + erubis + execjs (~> 2.0) + fast_blank + fastimage (~> 2.0) + hamster (~> 3.0) + hashie (~> 3.4) + i18n (~> 1.6.0) + listen (~> 3.0) + memoist (~> 0.14) + padrino-helpers (~> 0.15.0) + parallel + rack (>= 1.4.5, < 3) + sassc (~> 2.0) + servolux + tilt (~> 2.0.9) + toml + uglifier (~> 3.0) + webrick + middleman-livereload (3.4.7) + em-websocket (~> 0.5.1) + middleman-core (>= 3.3) + rack-livereload (~> 0.3.15) + middleman-search-gds (0.11.2) + execjs (~> 2.6) + middleman-core (>= 3.2) + nokogiri (~> 1.6) + middleman-sprockets (4.0.0) + middleman-core (~> 4.0) + sprockets (>= 3.0) + middleman-syntax (3.2.0) + middleman-core (>= 3.2) + rouge (~> 3.2) + minitest (5.18.0) + multi_json (1.15.0) + nokogiri (1.16.5-x86_64-linux) + racc (~> 1.4) + openapi3_parser (0.9.2) + commonmarker (~> 0.17) + padrino-helpers (0.15.3) + i18n (>= 0.6.7, < 2) + padrino-support (= 0.15.3) + tilt (>= 1.4.1, < 3) + padrino-support (0.15.3) + parallel (1.22.1) + parslet (2.0.0) + public_suffix (5.0.1) + racc (1.7.3) + rack (2.2.8.1) + rack-livereload (0.3.17) + rack + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.1) + rexml (3.3.9) + rouge (3.30.0) + sass (3.4.25) + sassc (2.4.0) + ffi (~> 1.9) + servolux (0.13.0) + sprockets (4.2.0) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + temple (0.10.0) + thor (1.2.1) + tilt (2.0.11) + toml (0.3.0) + parslet (>= 1.8.0, < 3.0.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uglifier (3.2.0) + execjs (>= 0.3.0, < 3) + webrick (1.8.2) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + govuk_tech_docs + tzinfo-data + wdm (~> 0.1.0) + +BUNDLED WITH + 2.3.26 diff --git a/projects/assess-for-early-release-and-delius/tech-docs/config.rb b/projects/assess-for-early-release-and-delius/tech-docs/config.rb new file mode 100644 index 0000000000..76c77d53dd --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/config.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "govuk_tech_docs" + +GovukTechDocs.configure(self) + +activate :relative_assets +set :relative_links, true diff --git a/projects/assess-for-early-release-and-delius/tech-docs/config/tech-docs.yml b/projects/assess-for-early-release-and-delius/tech-docs/config/tech-docs.yml new file mode 100644 index 0000000000..646e660be3 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/config/tech-docs.yml @@ -0,0 +1,44 @@ +# Host to use for canonical URL generation (without trailing slash) +host: https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/assess-for-early-release-and-delius + +# Header-related options +service_name: HMPPS Assess For Early Release And Delius +service_link: https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/assess-for-early-release-and-delius + +# Links to show on right-hand-side of header +header_links: + Home: https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs + GitHub: https://github.com/ministryofjustice/hmpps-probation-integration-services#readme + Slack: https://mojdt.slack.com/archives/C02HQ4M2YQN # #probation-integration-tech channel + +# Enables search functionality. This indexes pages only and is not recommended for single-page sites. +enable_search: true + +# Tracking ID from Google Analytics (e.g. UA-XXXX-Y) +ga_tracking_id: + +# Enable multipage navigation in the sidebar +multipage_nav: true + +# Enable collapsible navigation in the sidebar +collapsible_nav: true + +# Table of contents depth – how many levels to include in the table of contents. +# If your ToC is too long, reduce this number and we'll only show higher-level +# headings. +max_toc_heading_level: 2 + +# Prevent robots from indexing (e.g. whilst in development) +prevent_indexing: false + +# Contribution +show_contribution_banner: true +github_repo: ministryofjustice/hmpps-probation-integration-services +github_branch: main + +# Slack +owner_slack_workspace: mojdt +default_owner_slack: '#probation-integration-tech' + +# OpenAPI +api_path: https://assess-for-early-release-and-delius-dev.hmpps.service.justice.gov.uk/v3/api-docs.yaml diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/api-reference.html.md.erb b/projects/assess-for-early-release-and-delius/tech-docs/source/api-reference.html.md.erb new file mode 100644 index 0000000000..a21752cfae --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/api-reference.html.md.erb @@ -0,0 +1,19 @@ +--- +title: API Reference +source_url: 'https://github.com/ministryofjustice/hmpps-probation-integration-services/blob/main/projects/assess-for-early-release-and-delius/tech-docs/source/api-reference.html.md.erb' +weight: 20 +--- + +
    + + API Reference +
    + + +The following documentation is also available in these formats: + +* [OpenAPI JSON](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/assess-for-early-release-and-delius/api-docs.json) +* [OpenAPI YAML](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/assess-for-early-release-and-delius/api-docs.yaml) +* [Swagger UI](https://assess-for-early-release-and-delius-dev.hmpps.service.justice.gov.uk/swagger-ui/index.html) + +api> diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/index.html.md.erb b/projects/assess-for-early-release-and-delius/tech-docs/source/index.html.md.erb new file mode 100644 index 0000000000..52d19debb8 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/index.html.md.erb @@ -0,0 +1,7 @@ +--- +title: About +source_url: 'https://github.com/ministryofjustice/hmpps-probation-integration-services/blob/main/projects/assess-for-early-release-and-delius/tech-docs/source/index.html.md.erb' +weight: 10 +--- + +<%= URI.open('https://raw.githubusercontent.com/ministryofjustice/hmpps-probation-integration-services/main/projects/assess-for-early-release-and-delius/README.md').read.gsub(/tech-docs\/source\//, "./") %> \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/javascripts/application.js b/projects/assess-for-early-release-and-delius/tech-docs/source/javascripts/application.js new file mode 100644 index 0000000000..8a5d80b842 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/javascripts/application.js @@ -0,0 +1 @@ +//= require govuk_tech_docs diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/print.css.scss b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/print.css.scss new file mode 100644 index 0000000000..82b181c017 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/print.css.scss @@ -0,0 +1,3 @@ +$is-print: true; + +@import "govuk_tech_docs"; diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen-old-ie.css.scss b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen-old-ie.css.scss new file mode 100644 index 0000000000..da90cca5b0 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen-old-ie.css.scss @@ -0,0 +1,4 @@ +$is-ie: true; +$ie-version: 8; + +@import "govuk_tech_docs"; diff --git a/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen.css.scss b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen.css.scss new file mode 100644 index 0000000000..f0456338fd --- /dev/null +++ b/projects/assess-for-early-release-and-delius/tech-docs/source/stylesheets/screen.css.scss @@ -0,0 +1 @@ +@import "govuk_tech_docs"; diff --git a/settings.gradle.kts b/settings.gradle.kts index e897a719f8..c73ea07547 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,7 @@ rootProject.name = "probation-integration-services" include( // ⌄ add new projects here + "assess-for-early-release-and-delius", "justice-email-and-delius", "appointment-reminders-and-delius", "ims-and-delius", From 2f253ac81a13ae6086cdc1a36beabd9289f19e3f Mon Sep 17 00:00:00 2001 From: Marcus Aspin Date: Wed, 20 Nov 2024 15:47:00 +0000 Subject: [PATCH 4/6] Added note about imports to code formatting section (#4450) also moved code formatting to development section --- README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a1b558b2d9..88852a0e6c 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,24 @@ Docker or remote dependencies. To set up your development environment: 1. Open the project in [IntelliJ IDEA](https://www.jetbrains.com/idea/). Select "Import project from external model", then "Gradle". -2. To run the tests for a service, right-click the `src/test` folder in the project view and select "Run tests" (See [Test](#test)). +2. To run the tests for a service, right-click the `src/test` or `src/integrationTest` folder in the project view and + select "Run tests" (See [Test](#test)). 3. To start the service, use the pre-defined run configuration in `.idea/runConfigurations` (See [Run](#run)). +## Code formatting + +Kotlin code is formatted using IntelliJ IDEA's code formatter, +which follows the [Kotlin Coding Conventions](https://kotlinlang.org/docs/coding-conventions.html). + +GitHub Actions will automatically fix any formatting issues when you open a pull request. +You can also use **L** (macOS), +or **Ctrl+Alt+L** (Windows/Linux) to manually reformat your code in IntelliJ IDEA. +See [Reformat code](https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html). + +Note: The code formatter does not remove unused imports by default. You should +enable [Optimise on save](https://www.jetbrains.com/help/idea/creating-and-optimizing-imports.html#optimize-on-save) in +your IntelliJ IDEA settings to ensure you do not commit unused imports. + # Build IntelliJ will automatically build your code as needed. To build using Gradle, follow the instructions below. @@ -97,15 +112,6 @@ To build Docker images locally, run: ./gradlew jibDockerBuild ``` -## Code formatting -Kotlin code is formatted using IntelliJ IDEA's code formatter, -which follows the [Kotlin Coding Conventions](https://kotlinlang.org/docs/coding-conventions.html). - -GitHub Actions will automatically fix any formatting issues when you open a pull request. -You can also use **L** (macOS), -or **Ctrl+Alt+L** (Windows/Linux) to manually reformat your code in IntelliJ IDEA. -See [Reformat file](https://www.jetbrains.com/guide/java/tips/reformat-file/). - # Run ## IntelliJ In IntelliJ IDEA, a Spring Boot [run configuration](https://www.jetbrains.com/help/idea/run-debug-configuration.html) is From bc559ecc9f551f130cd07ec7aec3e1265b747fb9 Mon Sep 17 00:00:00 2001 From: Marcus Aspin Date: Wed, 20 Nov 2024 15:47:15 +0000 Subject: [PATCH 5/6] PI-2564 Copy API endpoints from CVL (#4452) --- .../build.gradle.kts | 3 + .../deploy/values-dev.yml | 2 - .../deploy/values-preprod.yml | 2 - .../deploy/values.yaml | 3 + .../justice/digital/hmpps/data/DataLoader.kt | 73 +++++++- .../hmpps/data/generator/CaseloadGenerator.kt | 111 +++++++++++ .../hmpps/data/generator/PersonGenerator.kt | 31 +++ .../hmpps/data/generator/ProviderGenerator.kt | 141 ++++++++++++++ .../hmpps/data/generator/StaffGenerator.kt | 30 +++ .../src/dev/resources/schema.ldif | 25 +++ .../digital/hmpps/CaseloadIntegrationTest.kt | 70 +++++++ .../justice/digital/hmpps/IntegrationTest.kt | 176 +++++++++++++++++- .../uk/gov/justice/digital/hmpps/App.kt | 3 +- .../hmpps/api/model/ManagedOffender.kt | 11 ++ .../digital/hmpps/api/model/Manager.kt | 30 +++ .../digital/hmpps/api/model/OfficeAddress.kt | 56 ++++++ .../justice/digital/hmpps/api/model/Staff.kt | 30 +++ .../api/resource/ProbationCaseResource.kt | 19 ++ .../hmpps/api/resource/StaffResource.kt | 33 ++++ .../hmpps/api/resource/TeamResource.kt | 18 ++ .../digital/hmpps/controller/ApiController.kt | 17 -- .../justice/digital/hmpps/entity/Caseload.kt | 47 +++++ .../justice/digital/hmpps/entity/LdapUser.kt | 23 +++ .../justice/digital/hmpps/entity/Person.kt | 25 +++ .../digital/hmpps/entity/PersonManager.kt | 52 ++++++ .../justice/digital/hmpps/entity/Provider.kt | 160 ++++++++++++++++ .../gov/justice/digital/hmpps/entity/Staff.kt | 80 ++++++++ .../digital/hmpps/service/ManagerService.kt | 86 +++++++++ .../digital/hmpps/service/StaffService.kt | 81 ++++++++ .../digital/hmpps/service/TeamService.kt | 19 ++ .../src/main/resources/application.yml | 9 +- .../hmpps/api/resource/StaffResourceTest.kt | 31 +++ .../hmpps/api/resource/TeamResourceTest.kt | 33 ++++ .../service/ResponsibleManagerServiceTest.kt | 44 +++++ .../digital/hmpps/service/StaffServiceTest.kt | 43 +++++ .../digital/hmpps/service/TeamServiceTest.kt | 31 +++ 36 files changed, 1615 insertions(+), 33 deletions(-) create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt create mode 100644 projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt create mode 100644 projects/assess-for-early-release-and-delius/src/dev/resources/schema.ldif create mode 100644 projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CaseloadIntegrationTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/ManagedOffender.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Manager.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/OfficeAddress.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Staff.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResource.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResource.kt delete mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Caseload.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/LdapUser.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Person.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/PersonManager.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Provider.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Staff.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ManagerService.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/StaffService.kt create mode 100644 projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/TeamService.kt create mode 100644 projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResourceTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResourceTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ResponsibleManagerServiceTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/StaffServiceTest.kt create mode 100644 projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/TeamServiceTest.kt diff --git a/projects/assess-for-early-release-and-delius/build.gradle.kts b/projects/assess-for-early-release-and-delius/build.gradle.kts index a089a2f210..b7a0ac1c3d 100644 --- a/projects/assess-for-early-release-and-delius/build.gradle.kts +++ b/projects/assess-for-early-release-and-delius/build.gradle.kts @@ -12,12 +12,14 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-data-ldap") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation(libs.springdoc) dev(project(":libs:dev-tools")) + dev("com.unboundid:unboundid-ldapsdk") dev("com.h2database:h2") dev("org.testcontainers:oracle-xe") @@ -31,6 +33,7 @@ configure { jacocoExclusions = listOf( "**/config/**", "**/entity/**", + "**/ldap/**", "**/AppKt.class" ) } diff --git a/projects/assess-for-early-release-and-delius/deploy/values-dev.yml b/projects/assess-for-early-release-and-delius/deploy/values-dev.yml index 41baa373a1..1996330d35 100644 --- a/projects/assess-for-early-release-and-delius/deploy/values-dev.yml +++ b/projects/assess-for-early-release-and-delius/deploy/values-dev.yml @@ -1,5 +1,3 @@ -enabled: false # TODO set this to true when you're ready to deploy your service - generic-service: ingress: host: assess-for-early-release-and-delius-dev.hmpps.service.justice.gov.uk diff --git a/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml b/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml index 23a555dccd..aa341f8d1c 100644 --- a/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml +++ b/projects/assess-for-early-release-and-delius/deploy/values-preprod.yml @@ -1,5 +1,3 @@ -enabled: false # TODO set this to true when you're ready to deploy your service - generic-service: ingress: host: assess-for-early-release-and-delius-preprod.hmpps.service.justice.gov.uk diff --git a/projects/assess-for-early-release-and-delius/deploy/values.yaml b/projects/assess-for-early-release-and-delius/deploy/values.yaml index 9170a7faa4..a47d12cc30 100644 --- a/projects/assess-for-early-release-and-delius/deploy/values.yaml +++ b/projects/assess-for-early-release-and-delius/deploy/values.yaml @@ -12,6 +12,9 @@ generic-service: namespace_secrets: common: SPRING_DATASOURCE_URL: DB_URL + SPRING_LDAP_URLS: LDAP_URL + SPRING_LDAP_USERNAME: LDAP_USERNAME + SPRING_LDAP_PASSWORD: LDAP_PASSWORD assess-for-early-release-and-delius-database: SPRING_DATASOURCE_USERNAME: DB_USERNAME SPRING_DATASOURCE_PASSWORD: DB_PASSWORD diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index f6ea94c9a7..df093edc47 100644 --- a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -1,17 +1,20 @@ 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 uk.gov.justice.digital.hmpps.data.generator.UserGenerator +import org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.data.generator.* import uk.gov.justice.digital.hmpps.user.AuditUserRepository @Component @ConditionalOnProperty("seed.database") class DataLoader( - private val auditUserRepository: AuditUserRepository + private val auditUserRepository: AuditUserRepository, + private val entityManager: EntityManager ) : ApplicationListener { @PostConstruct @@ -19,7 +22,71 @@ class DataLoader( auditUserRepository.save(UserGenerator.AUDIT_USER) } + @Transactional override fun onApplicationEvent(are: ApplicationReadyEvent) { - // Perform dev/test database setup here, using JPA repositories and generator classes... + entityManager.persist(ProviderGenerator.DEFAULT_PROVIDER) + entityManager.persist(StaffGenerator.PDUHEAD) + entityManager.persist(StaffGenerator.DEFAULT_PDUSTAFF_USER) + entityManager.persist(ProviderGenerator.DEFAULT_BOROUGH) + entityManager.persist(ProviderGenerator.DEFAULT_DISTRICT) + + createOfficeLocationsAndDistricts() + + entityManager.persist(ProviderGenerator.DEFAULT_TEAM) + entityManager.persist(ProviderGenerator.TEAM_ENDED_OR_NULL_LOCATIONS) + + StaffGenerator.DEFAULT = StaffGenerator.generateStaff( + StaffGenerator.DEFAULT.code, + StaffGenerator.DEFAULT.forename, + StaffGenerator.DEFAULT.surname, + listOf(ProviderGenerator.DEFAULT_TEAM), + ProviderGenerator.DEFAULT_PROVIDER, + StaffGenerator.DEFAULT.middleName, + StaffGenerator.DEFAULT.user, + StaffGenerator.DEFAULT.id + ) + entityManager.persist(StaffGenerator.DEFAULT) + + entityManager.persist(StaffGenerator.DEFAULT_STAFF_USER) + entityManager.flush() + + entityManager.persist(PersonGenerator.DEFAULT_PERSON) + entityManager.persist(PersonGenerator.PERSON_ENDED_TEAM_LOCATION) + entityManager.persist(PersonGenerator.DEFAULT_CM) + entityManager.persist(PersonGenerator.CM_ENDED_TEAM_LOCATION) + + val person = PersonGenerator.generatePerson("N123456").also(entityManager::persist) + PersonGenerator.generateManager(person).also(entityManager::persist) + + createCaseloadData() + } + + private fun createOfficeLocationsAndDistricts() { + entityManager.persistAll( + ProviderGenerator.DISTRICT_BRK, + ProviderGenerator.DISTRICT_MKY, + ProviderGenerator.DISTRICT_OXF, + ProviderGenerator.LOCATION_BRK_1, + ProviderGenerator.LOCATION_BRK_2, + ProviderGenerator.LOCATION_ENDED, + ProviderGenerator.LOCATION_NULL + ) + } + + private fun createCaseloadData() { + entityManager.persistAll( + CaseloadGenerator.TEAM1, + CaseloadGenerator.STAFF1, + CaseloadGenerator.STAFF2, + CaseloadGenerator.CASELOAD_ROLE_OM_1, + CaseloadGenerator.CASELOAD_ROLE_OM_2, + CaseloadGenerator.CASELOAD_ROLE_OM_3, + CaseloadGenerator.CASELOAD_ROLE_OM_4, + CaseloadGenerator.CASELOAD_ROLE_OS_1 + ) + } + + private fun EntityManager.persistAll(vararg entities: Any) { + entities.forEach { persist(it) } } } diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt new file mode 100644 index 0000000000..7fcf7c9bce --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt @@ -0,0 +1,111 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.api.model.Name +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator.DEFAULT_TEAM +import uk.gov.justice.digital.hmpps.entity.Caseload +import uk.gov.justice.digital.hmpps.entity.Staff +import uk.gov.justice.digital.hmpps.entity.Team +import uk.gov.justice.digital.hmpps.service.asStaff +import uk.gov.justice.digital.hmpps.service.asTeam +import java.time.LocalDate + +object CaseloadGenerator { + + val STAFF1 = StaffGenerator.generateStaff("STCDE01", "Bob", "Smith") + val STAFF2 = StaffGenerator.generateStaff("STCDE02", "Joe", "Bloggs") + + val TEAM1 = ProviderGenerator.generateTeam("N02BDT") + + val CASELOAD_ROLE_OM_1 = generateCaseload( + staff = STAFF1, + team = DEFAULT_TEAM, + crn = "crn0001", + firstName = "John", + secondName = "x", + surname = "Brown", + allocationDate = LocalDate.of(2024, 1, 8), + roleCode = Caseload.CaseloadRole.OFFENDER_MANAGER.value + ) + + val CASELOAD_ROLE_OM_2 = generateCaseload( + staff = STAFF1, + team = DEFAULT_TEAM, + crn = "crn0022", + firstName = "Jane", + secondName = "y", + surname = "Doe", + allocationDate = LocalDate.of(2024, 1, 9), + roleCode = Caseload.CaseloadRole.OFFENDER_MANAGER.value + ) + + val CASELOAD_ROLE_OM_3 = generateCaseload( + staff = STAFF2, + team = DEFAULT_TEAM, + crn = "crn0077", + firstName = "Ano", + secondName = "no", + surname = "mys", + allocationDate = LocalDate.of(2024, 1, 10), + roleCode = Caseload.CaseloadRole.OFFENDER_MANAGER.value + ) + + val CASELOAD_ROLE_OM_4 = generateCaseload( + staff = STAFF2, + team = TEAM1, + crn = "crn0078", + firstName = "Joe", + secondName = "Denis", + surname = "Doe", + allocationDate = LocalDate.of(2024, 1, 10), + roleCode = Caseload.CaseloadRole.OFFENDER_MANAGER.value + ) + + val CASELOAD_ROLE_OS_1 = generateCaseload( + staff = STAFF2, + team = DEFAULT_TEAM, + crn = "crn0088", + firstName = "Robert", + secondName = "Alan", + surname = "Brown", + roleCode = Caseload.CaseloadRole.ORDER_SUPERVISOR.value + ) + + val MANAGED_OFFENDER = generateManagedOffender(CASELOAD_ROLE_OM_1, STAFF1, DEFAULT_TEAM) + + fun generateCaseload( + staff: Staff, + team: Team, + allocationDate: LocalDate? = LocalDate.now(), + roleCode: String, + crn: String, + firstName: String, + secondName: String?, + surname: String, + startDate: LocalDate? = LocalDate.now(), + id: Long = IdGenerator.getAndIncrement() + ) = Caseload( + staff, + team, + allocationDate, + roleCode, + crn, + firstName, + secondName, + surname, + startDate, + id + ) + + fun generateManagedOffender( + caseload: Caseload, + staff: Staff, + team: Team + ) = ManagedOffender( + caseload.crn, + Name(caseload.firstName, caseload.secondName, caseload.surname), + caseload.allocationDate, + staff.asStaff(), + team.asTeam() + ) +} diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt new file mode 100644 index 0000000000..c0f8fb2405 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -0,0 +1,31 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.entity.* + +object PersonGenerator { + val DEFAULT_PERSON = generatePerson("T123456") + val PERSON_ENDED_TEAM_LOCATION = generatePerson("T123457") + val DEFAULT_CM = generateManager(DEFAULT_PERSON) + val CM_ENDED_TEAM_LOCATION = + generateManager(person = PERSON_ENDED_TEAM_LOCATION, team = ProviderGenerator.TEAM_ENDED_OR_NULL_LOCATIONS) + + fun generatePerson( + crn: String, + softDeleted: Boolean = false, + id: Long = IdGenerator.getAndIncrement() + ) = Person( + crn, + softDeleted, + id + ) + + fun generateManager( + person: Person, + provider: Provider = ProviderGenerator.DEFAULT_PROVIDER, + team: Team = ProviderGenerator.DEFAULT_TEAM, + staff: Staff = StaffGenerator.DEFAULT, + softDeleted: Boolean = false, + active: Boolean = true, + id: Long = IdGenerator.getAndIncrement() + ) = PersonManager(person, provider, team, staff, softDeleted, active, id) +} diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt new file mode 100644 index 0000000000..a0e2885da0 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt @@ -0,0 +1,141 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import java.time.LocalDate + +object ProviderGenerator { + val DEFAULT_PROVIDER = generateProvider("N01") + val DEFAULT_BOROUGH = generateBorough("N01B") + val DEFAULT_DISTRICT = generateDistrict("N01D") + val DISTRICT_BRK = generateDistrict("TVP_BRK", "Berkshire") + val DISTRICT_OXF = generateDistrict("TVP_OXF", "Oxfordshire") + val DISTRICT_MKY = generateDistrict("TVP_MKY", "Milton Keynes") + + val LOCATION_BRK_1 = generateLocation( + code = "TVP_BRK", + description = "Bracknell Office", + buildingNumber = "21", + streetName = "Some Place", + district = "District 1", + town = "Hearth", + postcode = "H34 7TH", + ldu = DISTRICT_BRK + ) + + val LOCATION_BRK_2 = generateLocation( + code = "TVP_RCC", + description = "Reading Office", + buildingNumber = "23", + buildingName = "The old hall", + streetName = "Another Place", + district = "District 2", + town = "Reading", + postcode = "RG1 3EH", + ldu = DISTRICT_BRK + ) + val LOCATION_ENDED = generateLocation( + code = "TVP_RCC", + description = "Reading Office", + buildingNumber = "23", + buildingName = "The old hall", + streetName = "Another Place", + district = "District 2", + town = "Reading", + postcode = "RG1 3EH", + endDate = LocalDate.now().minusDays(1), + ldu = DISTRICT_BRK + ) + + val LOCATION_NULL = generateLocation( + code = "TVP_RCC", + description = "Null office", + ldu = DEFAULT_DISTRICT + ) + + val DEFAULT_TEAM = generateTeam("N01BDT") + + val TEAM_ENDED_OR_NULL_LOCATIONS = generateTeam( + addresses = listOf( + LOCATION_BRK_1, + LOCATION_BRK_2, + LOCATION_ENDED, + LOCATION_NULL + ), code = "N01BDT" + ) + + fun generateProvider( + code: String, + description: String = "Description of $code", + id: Long = IdGenerator.getAndIncrement(), + endDate: LocalDate? = null + ) = uk.gov.justice.digital.hmpps.entity.Provider(code, description, id, endDate) + + fun generateBorough( + code: String, + description: String = "Description of $code", + id: Long = IdGenerator.getAndIncrement(), + ) = uk.gov.justice.digital.hmpps.entity.Borough(code, description, id, listOf(), DEFAULT_PROVIDER) + + fun generateDistrict( + code: String, + description: String = "Description of $code", + borough: uk.gov.justice.digital.hmpps.entity.Borough = DEFAULT_BOROUGH, + id: Long = IdGenerator.getAndIncrement() + ) = uk.gov.justice.digital.hmpps.entity.District(code, description, borough, id) + + fun generateTeam( + code: String, + description: String = "Description of $code", + telephone: String? = "12345", + emailAddress: String? = "testemail", + district: uk.gov.justice.digital.hmpps.entity.District = DEFAULT_DISTRICT, + addresses: List = listOf( + LOCATION_BRK_1, + LOCATION_BRK_2 + ), + startDate: LocalDate = LocalDate.now(), + endDate: LocalDate? = null, + id: Long = IdGenerator.getAndIncrement() + ) = uk.gov.justice.digital.hmpps.entity.Team( + code, + description, + telephone, + emailAddress, + district, + addresses, + startDate, + endDate, + id + ) + + fun generateLocation( + code: String, + description: String, + buildingName: String? = null, + buildingNumber: String? = null, + streetName: String? = null, + district: String? = null, + town: String? = null, + county: String? = null, + postcode: String? = null, + telephoneNumber: String? = null, + startDate: LocalDate = LocalDate.now(), + endDate: LocalDate? = null, + ldu: uk.gov.justice.digital.hmpps.entity.District, + id: Long = IdGenerator.getAndIncrement() + ) = uk.gov.justice.digital.hmpps.entity.OfficeLocation( + code, + description, + buildingName, + buildingNumber, + streetName, + district, + town, + county, + postcode, + telephoneNumber, + startDate, + endDate, + ldu, + id + ) +} diff --git a/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt new file mode 100644 index 0000000000..5f0a533eb3 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/StaffGenerator.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps.data.generator + +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator.DEFAULT_BOROUGH +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator.DEFAULT_PROVIDER +import uk.gov.justice.digital.hmpps.entity.* +import uk.gov.justice.digital.hmpps.set + +object StaffGenerator { + val PDUHEAD = generateStaff("N01BDT2", "Bob", "Smith").also { DEFAULT_BOROUGH.set(Borough::pduHeads, listOf(it)) } + val DEFAULT_PDUSTAFF_USER = generateStaffUser("bob-smith", PDUHEAD) + var DEFAULT = generateStaff("N01BDT1", "John", "Smith", teams = listOf(ProviderGenerator.DEFAULT_TEAM)) + val DEFAULT_STAFF_USER = generateStaffUser("john-smith", DEFAULT) + + fun generateStaff( + code: String, + forename: String, + surname: String, + teams: List = listOf(), + provider: Provider = DEFAULT_PROVIDER, + middleName: String? = null, + user: StaffUser? = null, + id: Long = IdGenerator.getAndIncrement() + ) = Staff(code, forename, surname, middleName, user, id, teams, provider).apply { user?.set("staff", this) } + + fun generateStaffUser( + username: String, + staff: Staff? = null, + id: Long = IdGenerator.getAndIncrement() + ) = StaffUser(staff, username, id).apply { staff?.set("user", this) } +} diff --git a/projects/assess-for-early-release-and-delius/src/dev/resources/schema.ldif b/projects/assess-for-early-release-and-delius/src/dev/resources/schema.ldif new file mode 100644 index 0000000000..9528a41c52 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/dev/resources/schema.ldif @@ -0,0 +1,25 @@ +dn: ou=Users,dc=moj,dc=com +objectclass: top +objectclass: organizationalUnit +ou: Users + +dn: cn=john-smith,ou=Users,dc=moj,dc=com +objectclass: top +objectclass: inetOrgPerson +cn: john-smith +sn: Staff +mail: john.smith@moj.gov.uk +telephoneNumber: 10101010101 + +dn: cn=bob-smith,ou=Users,dc=moj,dc=com +objectclass: top +objectclass: inetOrgPerson +cn: bob-smith +sn: Staff +mail: bob.smith@moj.gov.uk +telephoneNumber: 20202020202 + +dn: cn=ndRoleCatalogue,ou=Users,dc=moj,dc=com +description: Role Catalogue +objectclass: top +cn: ndRoleCatalogue \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CaseloadIntegrationTest.kt b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CaseloadIntegrationTest.kt new file mode 100644 index 0000000000..b8623570ac --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CaseloadIntegrationTest.kt @@ -0,0 +1,70 @@ +package uk.gov.justice.digital.hmpps + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +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.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import uk.gov.justice.digital.hmpps.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.CASELOAD_ROLE_OM_1 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.CASELOAD_ROLE_OM_2 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.CASELOAD_ROLE_OM_3 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.CASELOAD_ROLE_OM_4 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.STAFF1 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.STAFF2 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.TEAM1 +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.generateManagedOffender +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator.DEFAULT_TEAM +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken + +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = RANDOM_PORT) +internal class CaseloadIntegrationTest { + @Autowired + lateinit var mockMvc: MockMvc + + @ParameterizedTest + @MethodSource("caseloadArgs") + fun getManagedOffenders(url: String, expected: List?) { + val res = mockMvc.perform(get(url).withToken()).andExpect(status().isOk) + .andReturn().response.contentAsJson>() + assertThat(res, equalTo(expected)) + } + + companion object { + @JvmStatic + fun caseloadArgs(): List = listOf( + Arguments.of("/staff/STCDEXX/caseload/managed-offenders", listOf()), Arguments.of( + "/staff/STCDE01/caseload/managed-offenders", listOf( + generateManagedOffender(CASELOAD_ROLE_OM_1, STAFF1, DEFAULT_TEAM), + generateManagedOffender(CASELOAD_ROLE_OM_2, STAFF1, DEFAULT_TEAM) + ) + ), Arguments.of( + "/staff/STCDE02/caseload/managed-offenders", listOf( + generateManagedOffender(CASELOAD_ROLE_OM_3, STAFF2, DEFAULT_TEAM), + generateManagedOffender(CASELOAD_ROLE_OM_4, STAFF2, TEAM1) + ) + ), Arguments.of( + "/team/N01BDT/caseload/managed-offenders", listOf( + generateManagedOffender(CASELOAD_ROLE_OM_3, STAFF2, DEFAULT_TEAM), + generateManagedOffender(CASELOAD_ROLE_OM_2, STAFF1, DEFAULT_TEAM), + generateManagedOffender(CASELOAD_ROLE_OM_1, STAFF1, DEFAULT_TEAM) + ) + ), Arguments.of( + "/team/N02BDT/caseload/managed-offenders", listOf( + generateManagedOffender(CASELOAD_ROLE_OM_4, STAFF2, TEAM1) + ) + ), Arguments.of( + "/team/N03BDT/caseload/managed-offenders", listOf() + ) + ) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index d9006c74c5..e7110210d7 100644 --- a/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/assess-for-early-release-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -1,16 +1,32 @@ package uk.gov.justice.digital.hmpps +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.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT -import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import uk.gov.justice.digital.hmpps.api.model.Manager +import uk.gov.justice.digital.hmpps.api.model.OfficeAddress +import uk.gov.justice.digital.hmpps.api.model.PDUHead +import uk.gov.justice.digital.hmpps.api.model.StaffName +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator +import uk.gov.justice.digital.hmpps.data.generator.StaffGenerator +import uk.gov.justice.digital.hmpps.entity.asAddress +import uk.gov.justice.digital.hmpps.service.asManager +import uk.gov.justice.digital.hmpps.service.asPDUHead +import uk.gov.justice.digital.hmpps.service.asStaffName +import uk.gov.justice.digital.hmpps.service.asTeam +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withJson import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken -import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @AutoConfigureMockMvc @SpringBootTest(webEnvironment = RANDOM_PORT) @@ -18,13 +34,159 @@ internal class IntegrationTest { @Autowired lateinit var mockMvc: MockMvc - @MockBean - lateinit var telemetryService: TelemetryService + @Test + fun `returns responsible officer details`() { + val crn = PersonGenerator.DEFAULT_PERSON.crn + + val manager = mockMvc + .perform(get("/probation-case/$crn/responsible-community-manager").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson() + + + assertThat( + manager, + equalTo( + PersonGenerator.DEFAULT_CM.asManager().copy( + username = "john-smith", email = "john.smith@moj.gov.uk" + ) + ) + ) + } + + @Test + fun `returns responsible officer details for a list of CRNs`() { + val crn = PersonGenerator.DEFAULT_PERSON.crn + mockMvc + .perform(post("/probation-case/responsible-community-manager").withToken().withJson(listOf(crn))) + .andExpect(status().isOk) + .andExpect(jsonPath("size()", equalTo(1))) + .andExpect(jsonPath("$[0].code", equalTo("N01BDT1"))) + .andExpect(jsonPath("$[0].email", equalTo("john.smith@moj.gov.uk"))) + } + + @Test + fun `returns only active and non null team office locations`() { + val crn = PersonGenerator.PERSON_ENDED_TEAM_LOCATION.crn + val expectedAddresses: List = listOf( + ProviderGenerator.LOCATION_BRK_1.asAddress(), + ProviderGenerator.LOCATION_BRK_2.asAddress() + ) + val manager = mockMvc + .perform(get("/probation-case/$crn/responsible-community-manager").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson() + assertThat( + manager, + equalTo( + PersonGenerator.CM_ENDED_TEAM_LOCATION.asManager().copy( + username = "john-smith", email = "john.smith@moj.gov.uk", + team = ProviderGenerator.TEAM_ENDED_OR_NULL_LOCATIONS.asTeam().copy(addresses = expectedAddresses) + ) + ) + ) + } + + @Test + fun `returns 404 if no crn or community officer`() { + mockMvc.perform( + get("/probation-case/Z123456/responsible-community-manager") + .withToken() + ).andExpect(status().isNotFound) + } + + @Test + fun `returns staff details`() { + val username = StaffGenerator.DEFAULT_STAFF_USER.username + mockMvc + .perform(get("/staff/$username").withToken()) + .andExpect(status().isOk) + .andExpect(jsonPath("$.username", equalTo("john-smith"))) + .andExpect(jsonPath("$.email", equalTo("john.smith@moj.gov.uk"))) + .andExpect(jsonPath("$.telephoneNumber", equalTo("10101010101"))) + } + + @Test + fun `username is case-insensitive`() { + val username = StaffGenerator.DEFAULT_STAFF_USER.username.uppercase() + mockMvc + .perform(get("/staff/$username").withToken()) + .andExpect(status().isOk) + .andExpect(jsonPath("$.username", equalTo("john-smith"))) + .andExpect(jsonPath("$.email", equalTo("john.smith@moj.gov.uk"))) + .andExpect(jsonPath("$.telephoneNumber", equalTo("10101010101"))) + } + + @Test + fun `returns pdu heads`() { + val boroughCode = ProviderGenerator.DEFAULT_BOROUGH.code + + val pduHeads = mockMvc + .perform(get("/staff/$boroughCode/pdu-head").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson>() + + assertThat( + pduHeads, + equalTo( + listOf( + StaffGenerator.PDUHEAD.asPDUHead().copy(email = "bob.smith@moj.gov.uk") + ) + ) + ) + } + + @Test + fun `returns staff names for usernames`() { + val usernames = + listOf(StaffGenerator.DEFAULT_PDUSTAFF_USER.username, StaffGenerator.DEFAULT_STAFF_USER.username) + + val staffNames = mockMvc + .perform(post("/staff").withToken().withJson(usernames)) + .andExpect(status().isOk) + .andReturn().response.contentAsJson>() + + assertThat( + staffNames, + equalTo( + listOf( + StaffGenerator.PDUHEAD.asStaffName(), + StaffGenerator.DEFAULT.asStaffName() + ) + ) + ) + } + + @Test + fun `usernames are case-insensitive`() { + val usernames = listOf( + StaffGenerator.DEFAULT_PDUSTAFF_USER.username.uppercase(), + StaffGenerator.DEFAULT_STAFF_USER.username.uppercase() + ) + + val staffNames = mockMvc + .perform(post("/staff").withToken().withJson(usernames)) + .andExpect(status().isOk) + .andReturn().response.contentAsJson>() + + assertThat( + staffNames, + equalTo( + listOf( + StaffGenerator.PDUHEAD.asStaffName(), + StaffGenerator.DEFAULT.asStaffName() + ) + ) + ) + } @Test - fun `API call retuns a success response`() { + fun `returns staff by code`() { mockMvc - .perform(get("/example/123").withToken()) - .andExpect(status().is2xxSuccessful) + .perform(get("/staff/bycode/${StaffGenerator.DEFAULT.code}").withToken()) + .andExpect(status().isOk) + .andExpect(jsonPath("$.username", equalTo("john-smith"))) + .andExpect(jsonPath("$.email", equalTo("john.smith@moj.gov.uk"))) + .andExpect(jsonPath("$.telephoneNumber", equalTo("10101010101"))) } } diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt index c7faac5b26..2c6b3789ed 100644 --- a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/App.kt @@ -1,9 +1,10 @@ package uk.gov.justice.digital.hmpps import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration import org.springframework.boot.runApplication -@SpringBootApplication +@SpringBootApplication(exclude = [LdapRepositoriesAutoConfiguration::class]) class App fun main(args: Array) { diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/ManagedOffender.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/ManagedOffender.kt new file mode 100644 index 0000000000..f3f02c708b --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/ManagedOffender.kt @@ -0,0 +1,11 @@ +package uk.gov.justice.digital.hmpps.api.model + +import java.time.LocalDate + +data class ManagedOffender( + val crn: String, + val name: Name, + val allocationDate: LocalDate?, + val staff: Staff, + val team: Team? +) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Manager.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Manager.kt new file mode 100644 index 0000000000..ce92154082 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Manager.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps.api.model + +import java.time.LocalDate + +data class Manager( + val id: Long, + val code: String, + val name: Name, + val provider: Provider, + val team: Team, + val username: String?, + val email: String?, + val unallocated: Boolean +) + +data class Name(val forename: String, val middleName: String?, val surname: String) +data class Provider(val code: String, val description: String) +data class Team( + val code: String, val description: String, + val telephone: String?, + val emailAddress: String?, + val addresses: List?, + val district: District, + val borough: Borough, + val startDate: LocalDate, + val endDate: LocalDate? +) + +data class District(val code: String, val description: String, val borough: Borough) +data class Borough(val code: String, val description: String) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/OfficeAddress.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/OfficeAddress.kt new file mode 100644 index 0000000000..ad1bd42347 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/OfficeAddress.kt @@ -0,0 +1,56 @@ +package uk.gov.justice.digital.hmpps.api.model + +import java.time.LocalDate + +data class OfficeAddress( + val officeName: String, + val buildingName: String?, + val buildingNumber: String?, + val streetName: String?, + val district: String?, + val town: String?, + val county: String?, + val postcode: String?, + val ldu: String, + val telephoneNumber: String?, + val from: LocalDate, + val to: LocalDate? +) { + companion object { + fun from( + officeName: String, + buildingName: String?, + buildingNumber: String?, + streetName: String?, + district: String?, + town: String?, + county: String?, + postcode: String?, + ldu: String, + telephoneNumber: String?, + from: LocalDate, + to: LocalDate? + ): OfficeAddress? = + if ( + buildingName == null && buildingNumber == null && streetName == null && + district == null && town == null && county == null && postcode == null + ) { + null + } else { + OfficeAddress( + officeName, + buildingName, + buildingNumber, + streetName, + district, + town, + county, + postcode, + ldu, + telephoneNumber, + from, + to + ) + } + } +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Staff.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Staff.kt new file mode 100644 index 0000000000..686fa9f596 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Staff.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps.api.model + +data class Staff( + val id: Long, + val code: String, + val name: Name, + val teams: List, + val provider: Provider, + val username: String?, + val email: String?, + val telephoneNumber: String?, + val unallocated: Boolean, +) + +data class PDUHead( + val name: Name, + val email: String? +) + +data class StaffName( + val id: Long, + val name: Name, + val code: String, + val username: String? +) + +data class StaffEmail( + val code: String, + val email: String? +) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt new file mode 100644 index 0000000000..ae30bb218d --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt @@ -0,0 +1,19 @@ +package uk.gov.justice.digital.hmpps.api.resource + +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.* +import uk.gov.justice.digital.hmpps.api.model.Manager +import uk.gov.justice.digital.hmpps.api.model.StaffEmail +import uk.gov.justice.digital.hmpps.service.ManagerService + +@RestController +@RequestMapping("probation-case") +@PreAuthorize("hasRole('PROBATION_API__ASSESS_FOR_EARLY_RELEASE__CASE_DETAIL')") +class ProbationCaseResource(private val responsibleManagerService: ManagerService) { + @GetMapping("{crn}/responsible-community-manager") + fun findCommunityManager(@PathVariable crn: String): Manager = responsibleManagerService.findCommunityManager(crn) + + @PostMapping("/responsible-community-manager") + fun findCommunityManagerEmails(@RequestBody crns: List): List = + responsibleManagerService.findCommunityManagerEmails(crns) +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResource.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResource.kt new file mode 100644 index 0000000000..f46fdaaea5 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResource.kt @@ -0,0 +1,33 @@ +package uk.gov.justice.digital.hmpps.api.resource + +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.* +import uk.gov.justice.digital.hmpps.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.api.model.PDUHead +import uk.gov.justice.digital.hmpps.api.model.Staff +import uk.gov.justice.digital.hmpps.api.model.StaffName +import uk.gov.justice.digital.hmpps.service.StaffService + +@RestController +@RequestMapping("staff") +@PreAuthorize("hasRole('PROBATION_API__ASSESS_FOR_EARLY_RELEASE__CASE_DETAIL')") +class StaffResource( + private val staffService: StaffService +) { + @GetMapping("/{username}") + fun findStaff(@PathVariable username: String): Staff = staffService.findStaff(username) + + @GetMapping("/bycode/{code}") + fun findStaffByCode(@PathVariable code: String): Staff = staffService.findStaffByCode(code) + + @GetMapping("/{boroughCode}/pdu-head") + fun findPDUHead(@PathVariable boroughCode: String): List = staffService.findPDUHeads(boroughCode) + + @PostMapping + fun findStaffForUsernames(@RequestBody usernames: List): List = + staffService.findStaffForUsernames(usernames) + + @GetMapping("/{staffCode}/caseload/managed-offenders") + fun getManagedOffenders(@PathVariable staffCode: String): List = + staffService.getManagedOffenders(staffCode) +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResource.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResource.kt new file mode 100644 index 0000000000..bd43321bd3 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResource.kt @@ -0,0 +1,18 @@ +package uk.gov.justice.digital.hmpps.api.resource + +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.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.service.TeamService + +@RestController +@RequestMapping("team") +@PreAuthorize("hasRole('PROBATION_API__ASSESS_FOR_EARLY_RELEASE__CASE_DETAIL')") +class TeamResource(private val teamService: TeamService) { + @GetMapping("/{teamCode}/caseload/managed-offenders") + fun getManagedOffendersByTeam(@PathVariable teamCode: String): List = + teamService.getManagedOffendersByTeam(teamCode) +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt deleted file mode 100644 index 6e4f24c46f..0000000000 --- a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt +++ /dev/null @@ -1,17 +0,0 @@ -package uk.gov.justice.digital.hmpps.controller - -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.RestController - -@RestController -class ApiController { - @PreAuthorize("hasRole('EXAMPLE')") - @GetMapping(value = ["/example/{inputId}"]) - fun handle( - @PathVariable("inputId") inputId: String - ) { - // TODO Not yet implemented - } -} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Caseload.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Caseload.kt new file mode 100644 index 0000000000..09c38f951c --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Caseload.kt @@ -0,0 +1,47 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.springframework.data.jpa.domain.support.AuditingEntityListener +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDate + +interface CaseloadRepository : JpaRepository { + fun findByStaffCodeAndRoleCode(staffCode: String, role: String): List + fun findByTeamCodeAndRoleCodeOrderByAllocationDateDesc(staffCode: String, role: String): List +} + +@Immutable +@EntityListeners(AuditingEntityListener::class) +@Entity +@Table(name = "caseload") +class Caseload( + + @ManyToOne + @JoinColumn(name = "staff_employee_id") + val staff: Staff, + + @ManyToOne + @JoinColumn(name = "trust_provider_team_id") + val team: Team, + + val allocationDate: LocalDate?, + val roleCode: String, + + @Column(columnDefinition = "char(7)") + val crn: String, + + val firstName: String, + val secondName: String?, + val surname: String, + val startDate: LocalDate?, + + @Id + val caseloadId: Long +) { + enum class CaseloadRole(val value: String) { + OFFENDER_MANAGER("OM"), + ORDER_SUPERVISOR("OS") + } +} + diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/LdapUser.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/LdapUser.kt new file mode 100644 index 0000000000..f19a3064b4 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/LdapUser.kt @@ -0,0 +1,23 @@ +package uk.gov.justice.digital.hmpps.entity + +import org.springframework.ldap.odm.annotations.Attribute +import org.springframework.ldap.odm.annotations.DnAttribute +import org.springframework.ldap.odm.annotations.Entry +import org.springframework.ldap.odm.annotations.Id +import javax.naming.Name + +@Entry(objectClasses = ["inetOrgPerson", "top"]) +class LdapUser( + @Id + val dn: Name, + + @Attribute(name = "cn") + @DnAttribute(value = "cn", index = 0) + val username: String, + + @Attribute(name = "mail") + val email: String?, + + @Attribute(name = "telephoneNumber") + val telephoneNumber: String? +) \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Person.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Person.kt new file mode 100644 index 0000000000..e1cd658bc8 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Person.kt @@ -0,0 +1,25 @@ +package uk.gov.justice.digital.hmpps.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.SQLRestriction + +@Immutable +@Entity +@Table(name = "offender") +@SQLRestriction("soft_deleted = 0") +class Person( + + @Column(columnDefinition = "char(7)") + val crn: String, + + @Column(name = "soft_deleted", columnDefinition = "number") + val softDeleted: Boolean = false, + + @Id + @Column(name = "offender_id") + val id: Long +) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/PersonManager.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/PersonManager.kt new file mode 100644 index 0000000000..6b6ec03fa3 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/PersonManager.kt @@ -0,0 +1,52 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +import org.springframework.data.jpa.repository.EntityGraph +import org.springframework.data.jpa.repository.JpaRepository +import uk.gov.justice.digital.hmpps.exception.NotFoundException + +@Immutable +@Entity +@Table(name = "offender_manager") +@SQLRestriction("soft_deleted = 0 and active_flag = 1") +class PersonManager( + + @ManyToOne + @JoinColumn(name = "offender_id") + val person: Person, + + @ManyToOne + @JoinColumn(name = "probation_area_id") + val provider: Provider, + + @ManyToOne + @JoinColumn(name = "team_id") + val team: Team, + + @ManyToOne + @JoinColumn(name = "allocation_staff_id") + val staff: Staff, + + @Column(name = "soft_deleted", columnDefinition = "number") + val softDeleted: Boolean = false, + + @Column(name = "active_flag", columnDefinition = "number") + val active: Boolean = true, + + @Id + @Column(name = "offender_manager_id") + val id: Long +) + +interface PersonManagerRepository : JpaRepository { + @EntityGraph(attributePaths = ["person", "provider", "team", "staff.user"]) + fun findByPersonCrn(crn: String): PersonManager? + + @EntityGraph(attributePaths = ["person", "staff.user"]) + fun findByPersonCrnIn(crn: List): List +} + +fun PersonManagerRepository.getByCrn(crn: String) = + findByPersonCrn(crn) ?: throw NotFoundException("Person", "crn", crn) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Provider.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Provider.kt new file mode 100644 index 0000000000..898fed3843 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Provider.kt @@ -0,0 +1,160 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import uk.gov.justice.digital.hmpps.api.model.OfficeAddress +import java.time.LocalDate + +@Immutable +@Entity +@Table(name = "probation_area") +class Provider( + @Column(name = "code", columnDefinition = "char(3)") + val code: String, + + val description: String, + + @Id + @Column(name = "probation_area_id") + val id: Long, + + @Column(name = "end_date") + var endDate: LocalDate? = null +) + +@Immutable +@Entity +@Table(name = "team") +class Team( + + @Column(name = "code", columnDefinition = "char(6)") + val code: String, + + val description: String, + val telephone: String?, + val emailAddress: String?, + + @ManyToOne + @JoinColumn(name = "district_id") + val district: District, + + @ManyToMany + @JoinTable( + name = "team_office_location", + joinColumns = [JoinColumn(name = "team_id")], + inverseJoinColumns = [JoinColumn(name = "office_location_id")] + ) + @SQLRestriction("end_date is null or end_date > current_date") + val addresses: List, + + val startDate: LocalDate, + val endDate: LocalDate?, + + @Id + @Column(name = "team_id") + val id: Long +) + +@Immutable +@Entity +@Table(name = "district") +class District( + + @Column(name = "code") + val code: String, + + val description: String, + + @ManyToOne + @JoinColumn(name = "borough_id") + val borough: Borough, + + @Id + @Column(name = "district_id") + val id: Long +) + +@Immutable +@Entity +@Table(name = "borough") +class Borough( + + @Column(name = "code") + val code: String, + + val description: String, + + @Id + @Column(name = "borough_id") + val id: Long, + + @ManyToMany + @JoinTable( + name = "r_level_2_head_of_level_2", + joinColumns = [JoinColumn(name = "borough_id")], + inverseJoinColumns = [JoinColumn(name = "staff_id")] + ) + val pduHeads: List, + + @JoinColumn(name = "PROBATION_AREA_ID") + @OneToOne + val provider: Provider +) + +interface BoroughRepository : JpaRepository { + @Query( + """ + select b from Borough b + where b.code = :code + and (b.provider.endDate is null or b.provider.endDate > current_date) + """ + ) + fun findActiveByCode(code: String): Borough? +} + +@Immutable +@Entity +@Table(name = "office_location") +class OfficeLocation( + + @Column(name = "code", columnDefinition = "char(7)") + val code: String, + + val description: String, + val buildingName: String?, + val buildingNumber: String?, + val streetName: String?, + val district: String?, + val townCity: String?, + val county: String?, + val postcode: String?, + val telephoneNumber: String?, + val startDate: LocalDate, + val endDate: LocalDate?, + + @JoinColumn(name = "district_id") + @ManyToOne + val ldu: District, + + @Id + @Column(name = "office_location_id") + val id: Long +) + +fun OfficeLocation.asAddress() = OfficeAddress( + description, + buildingName, + buildingNumber, + streetName, + district, + townCity, + county, + postcode, + ldu.description, + telephoneNumber, + startDate, + endDate +) \ No newline at end of file diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Staff.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Staff.kt new file mode 100644 index 0000000000..397d6e5af8 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Staff.kt @@ -0,0 +1,80 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.springframework.data.jpa.repository.EntityGraph +import org.springframework.data.jpa.repository.JpaRepository +import java.util.* + +@Immutable +@Entity +@Table(name = "staff") +class Staff( + + @Column(name = "officer_code", columnDefinition = "char(7)") + val code: String, + + val forename: String, + val surname: String, + + @Column(name = "forename2") + val middleName: String? = null, + + @OneToOne(mappedBy = "staff") + val user: StaffUser? = null, + + @Id + @Column(name = "staff_id") + val id: Long, + + @ManyToMany + @JoinTable( + name = "staff_team", + joinColumns = [JoinColumn(name = "staff_id")], + inverseJoinColumns = [JoinColumn(name = "team_id")] + ) + val teams: List?, + + @ManyToOne + @JoinColumn(name = "probation_area_id") // Note: this column should not be used in general, because it can change whenever a user's teams changes. It's only used here for backward compatibility with Community API. + val provider: Provider, +) { + fun isUnallocated() = code.endsWith("U") +} + +@Entity +@Immutable +@Table(name = "user_") +class StaffUser( + + @OneToOne + @JoinColumn(name = "staff_id") + val staff: Staff? = null, + + @Column(name = "distinguished_name") + val username: String, + + @Id + @Column(name = "user_id") + val id: Long +) { + @Transient + var email: String? = null + + @Transient + var telephoneNumber: String? = null +} + +interface StaffRepository : JpaRepository { + @EntityGraph(attributePaths = ["user", "teams"]) + fun findByUserUsernameIgnoreCase(username: String): Staff? + + @EntityGraph(attributePaths = ["user", "teams"]) + fun findByCode(code: String): Staff? + + @EntityGraph(attributePaths = ["user", "teams"]) + override fun findById(id: Long): Optional + + @EntityGraph(attributePaths = ["user"]) + fun findByUserUsernameInIgnoreCase(usernames: List): List +} diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ManagerService.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ManagerService.kt new file mode 100644 index 0000000000..bd0080fab4 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ManagerService.kt @@ -0,0 +1,86 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.ldap.core.LdapTemplate +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.api.model.* +import uk.gov.justice.digital.hmpps.entity.Caseload +import uk.gov.justice.digital.hmpps.entity.PersonManager +import uk.gov.justice.digital.hmpps.entity.PersonManagerRepository +import uk.gov.justice.digital.hmpps.entity.Staff +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.ldap.findEmailByUsername + +@Service +class ManagerService( + private val ldapTemplate: LdapTemplate, + private val personManagerRepository: PersonManagerRepository +) { + fun findCommunityManager(crn: String): Manager = + personManagerRepository.findByPersonCrn(crn)?.let { ro -> + ro.staff.user?.apply { + email = ldapTemplate.findEmailByUsername(username) + } + ro.asManager() + } ?: throw NotFoundException("CommunityManager", "crn", crn) + + fun findCommunityManagerEmails(crns: List): List = + personManagerRepository.findByPersonCrnIn(crns).map { + StaffEmail(it.staff.code, it.staff.user?.username?.let { ldapTemplate.findEmailByUsername(it) }) + } +} + +fun PersonManager.asManager() = Manager( + staff.id, + staff.code, + staff.name(), + provider.asProvider(), + team.asTeam(), + staff.user?.username, + staff.user?.email, + staff.isUnallocated() +) + +fun Staff.name() = Name(forename, middleName, surname) +fun uk.gov.justice.digital.hmpps.entity.Provider.asProvider() = + uk.gov.justice.digital.hmpps.api.model.Provider(code, description) + +fun uk.gov.justice.digital.hmpps.entity.Team.asTeam() = uk.gov.justice.digital.hmpps.api.model.Team( + code, + description, + telephone, + emailAddress, + addresses.mapNotNull(uk.gov.justice.digital.hmpps.entity.OfficeLocation::asTeamAddress), + district.asDistrict(), + district.borough.asBorough(), + startDate, + endDate +) + +fun uk.gov.justice.digital.hmpps.entity.OfficeLocation.asTeamAddress() = OfficeAddress.from( + description, + buildingName, + buildingNumber, + streetName, + district, + townCity, + county, + postcode, + ldu.description, + telephoneNumber, + startDate, + endDate +) + +fun Caseload.asManagedOffender() = ManagedOffender( + crn, + Name(firstName, secondName, surname), + allocationDate, + staff.asStaff(), + team.asTeam() +) + +fun uk.gov.justice.digital.hmpps.entity.District.asDistrict() = + uk.gov.justice.digital.hmpps.api.model.District(code, description, borough.asBorough()) + +fun uk.gov.justice.digital.hmpps.entity.Borough.asBorough() = + uk.gov.justice.digital.hmpps.api.model.Borough(code, description) diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/StaffService.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/StaffService.kt new file mode 100644 index 0000000000..ff81f505da --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/StaffService.kt @@ -0,0 +1,81 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.ldap.core.LdapTemplate +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.api.model.PDUHead +import uk.gov.justice.digital.hmpps.api.model.Staff +import uk.gov.justice.digital.hmpps.api.model.StaffName +import uk.gov.justice.digital.hmpps.entity.BoroughRepository +import uk.gov.justice.digital.hmpps.entity.Caseload.CaseloadRole +import uk.gov.justice.digital.hmpps.entity.CaseloadRepository +import uk.gov.justice.digital.hmpps.entity.LdapUser +import uk.gov.justice.digital.hmpps.entity.StaffRepository +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.ldap.findByUsername + +@Service +class StaffService( + private val ldapTemplate: LdapTemplate, + private val staffRepository: StaffRepository, + private val boroughRepository: BoroughRepository, + private val caseloadRepository: CaseloadRepository, +) { + fun findStaff(username: String): Staff = staffRepository.findByUserUsernameIgnoreCase(username) + ?.let { ldapTemplate.populateUserDetails(it).asStaff() } + ?: throw NotFoundException("Staff", "username", username) + + fun findStaffByCode(code: String): Staff = staffRepository.findByCode(code) + ?.let { ldapTemplate.populateUserDetails(it).asStaff() } + ?: throw NotFoundException("Staff", "code", code) + + fun findPDUHeads(boroughCode: String): List = boroughRepository.findActiveByCode(boroughCode)?.pduHeads + ?.map { ldapTemplate.populateUserDetails(it).asPDUHead() } + ?: listOf() + + fun findStaffForUsernames(usernames: List): List = + staffRepository.findByUserUsernameInIgnoreCase(usernames).map { it.asStaffName() } + + fun getManagedOffenders(staffCode: String): List = + caseloadRepository.findByStaffCodeAndRoleCode( + staffCode, + CaseloadRole.OFFENDER_MANAGER.value + ).map { + it.asManagedOffender() + } + + private fun LdapTemplate.populateUserDetails(staff: uk.gov.justice.digital.hmpps.entity.Staff) = + staff.apply { + user?.apply { + ldapTemplate.findByUsername(username)?.let { + email = it.email + telephoneNumber = it.telephoneNumber + } + } + } +} + +fun uk.gov.justice.digital.hmpps.entity.Staff.asStaff() = Staff( + id, + code, + name(), + teams?.map { it.asTeam() } ?: listOf(), + provider.asProvider(), + user?.username, + user?.email, + user?.telephoneNumber, + isUnallocated() +) + +fun uk.gov.justice.digital.hmpps.entity.Staff.asPDUHead() = PDUHead( + name(), + user?.email +) + +fun uk.gov.justice.digital.hmpps.entity.Staff.asStaffName() = StaffName( + id, + name(), + code, + user?.username +) + diff --git a/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/TeamService.kt b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/TeamService.kt new file mode 100644 index 0000000000..4ae1983679 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/TeamService.kt @@ -0,0 +1,19 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.api.model.ManagedOffender +import uk.gov.justice.digital.hmpps.entity.Caseload.CaseloadRole +import uk.gov.justice.digital.hmpps.entity.CaseloadRepository + +@Service +class TeamService( + private val caseloadRepository: CaseloadRepository, +) { + fun getManagedOffendersByTeam(teamCode: String): List = + caseloadRepository.findByTeamCodeAndRoleCodeOrderByAllocationDateDesc( + teamCode, + CaseloadRole.OFFENDER_MANAGER.value + ).map { + it.asManagedOffender() + } +} diff --git a/projects/assess-for-early-release-and-delius/src/main/resources/application.yml b/projects/assess-for-early-release-and-delius/src/main/resources/application.yml index 18f07d6fe3..0a4dd92c9e 100644 --- a/projects/assess-for-early-release-and-delius/src/main/resources/application.yml +++ b/projects/assess-for-early-release-and-delius/src/main/resources/application.yml @@ -16,10 +16,14 @@ spring: query.mutation_strategy.global_temporary: create_tables: false drop_tables: false + ldap: + base: ou=Users,dc=moj,dc=com + base-environment: + java.naming.ldap.derefAliases: never threads.virtual.enabled: true oauth2.roles: - - EXAMPLE + - PROBATION_API__ASSESS_FOR_EARLY_RELEASE__CASE_DETAIL springdoc.default-produces-media-type: application/json @@ -41,6 +45,9 @@ server.shutdown: immediate 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 + ldap.embedded: + validation.enabled: false + base-dn: ${spring.ldap.base} seed.database: true wiremock.enabled: true diff --git a/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResourceTest.kt b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResourceTest.kt new file mode 100644 index 0000000000..f69de1ccf1 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/StaffResourceTest.kt @@ -0,0 +1,31 @@ +package uk.gov.justice.digital.hmpps.api.resource + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator.MANAGED_OFFENDER +import uk.gov.justice.digital.hmpps.service.StaffService + +@ExtendWith(MockitoExtension::class) +internal class StaffResourceTest { + + @Mock + lateinit var staffService: StaffService + + @InjectMocks + lateinit var resource: StaffResource + + @Test + fun `calls managed offenders endpoint`() { + whenever(staffService.getManagedOffenders("STCDE01")).thenReturn( + listOf(MANAGED_OFFENDER) + ) + val res = resource.getManagedOffenders("STCDE01") + assertThat(res[0].crn, equalTo("crn0001")) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResourceTest.kt b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResourceTest.kt new file mode 100644 index 0000000000..17b93d64ad --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/resource/TeamResourceTest.kt @@ -0,0 +1,33 @@ +package uk.gov.justice.digital.hmpps.api.resource + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator +import uk.gov.justice.digital.hmpps.service.TeamService + +@ExtendWith(MockitoExtension::class) +internal class TeamResourceTest { + + @Mock + lateinit var teamService: TeamService + + @InjectMocks + lateinit var resource: TeamResource + + @Test + fun `calls managed offenders endpoint`() { + whenever(teamService.getManagedOffendersByTeam("N01BDT")).thenReturn( + listOf( + CaseloadGenerator.MANAGED_OFFENDER + ) + ) + val res = resource.getManagedOffendersByTeam("N01BDT") + assertThat(res[0].crn, equalTo("crn0001")) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ResponsibleManagerServiceTest.kt b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ResponsibleManagerServiceTest.kt new file mode 100644 index 0000000000..b71c91ee74 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ResponsibleManagerServiceTest.kt @@ -0,0 +1,44 @@ +package uk.gov.justice.digital.hmpps.service + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers.any +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.ldap.core.AttributesMapper +import org.springframework.ldap.core.LdapTemplate +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.data.generator.StaffGenerator +import uk.gov.justice.digital.hmpps.entity.PersonManagerRepository + +@ExtendWith(MockitoExtension::class) +internal class ResponsibleManagerServiceTest { + + @Mock + lateinit var personManagerRepository: PersonManagerRepository + + @Mock + lateinit var ldapTemplate: LdapTemplate + + @InjectMocks + lateinit var service: ManagerService + + @Test + fun `does not call ldap when no staff user`() { + val person = PersonGenerator.generatePerson("L123456") + val staff = StaffGenerator.generateStaff("NoLdap", "No", "User") + val cm = PersonGenerator.generateManager(person, staff = staff) + + whenever(personManagerRepository.findByPersonCrn(person.crn)).thenReturn(cm) + + val res = service.findCommunityManager(person.crn) + assertThat(res, equalTo(cm.asManager())) + verify(ldapTemplate, never()).search(any(), any>()) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/StaffServiceTest.kt b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/StaffServiceTest.kt new file mode 100644 index 0000000000..873d007057 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/StaffServiceTest.kt @@ -0,0 +1,43 @@ +package uk.gov.justice.digital.hmpps.service + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.whenever +import org.springframework.ldap.core.LdapTemplate +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator +import uk.gov.justice.digital.hmpps.entity.BoroughRepository +import uk.gov.justice.digital.hmpps.entity.CaseloadRepository +import uk.gov.justice.digital.hmpps.entity.StaffRepository + +@ExtendWith(MockitoExtension::class) +internal class StaffServiceTest { + + @Mock + lateinit var ldapTemplate: LdapTemplate + + @Mock + lateinit var staffRepository: StaffRepository + + @Mock + lateinit var boroughRepository: BoroughRepository + + @Mock + lateinit var caseloadRepository: CaseloadRepository + + @InjectMocks + lateinit var service: StaffService + + @Test + fun `calls caseload repository`() { + whenever(caseloadRepository.findByStaffCodeAndRoleCode("STCDE01", "OM")).thenReturn( + listOf(CaseloadGenerator.CASELOAD_ROLE_OM_1) + ) + val res = service.getManagedOffenders(staffCode = "STCDE01") + assertThat(res[0].crn, equalTo("crn0001")) + } +} diff --git a/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/TeamServiceTest.kt b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/TeamServiceTest.kt new file mode 100644 index 0000000000..b7dfb80144 --- /dev/null +++ b/projects/assess-for-early-release-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/TeamServiceTest.kt @@ -0,0 +1,31 @@ +package uk.gov.justice.digital.hmpps.service + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator +import uk.gov.justice.digital.hmpps.entity.CaseloadRepository + +@ExtendWith(MockitoExtension::class) +internal class TeamServiceTest { + + @Mock + lateinit var caseloadRepository: CaseloadRepository + + @InjectMocks + lateinit var service: TeamService + + @Test + fun `calls caseload repository`() { + whenever(caseloadRepository.findByTeamCodeAndRoleCodeOrderByAllocationDateDesc("N01BDT", "OM")).thenReturn( + listOf(CaseloadGenerator.CASELOAD_ROLE_OM_2) + ) + val res = service.getManagedOffendersByTeam("N01BDT") + assertThat(res[0].crn, equalTo("crn0022")) + } +} From 8b87ca6499df775652ba2b283db56d8888c9b320 Mon Sep 17 00:00:00 2001 From: "probation-integration-bot[bot]" <177347787+probation-integration-bot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:06:27 +0000 Subject: [PATCH 6/6] Update Gradle Wrapper from 8.11 to 8.11.1 (#4453) Bump Gradle Wrapper to the latest version Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- .../api-client/gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 82dd18b204..eb1a55be0e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=57dafb5c2622c6cc08b993c85b7c06956a2f53536432a30ead46166dbca0f1e9 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/tools/ingress-testing/api-client/gradle/wrapper/gradle-wrapper.properties b/tools/ingress-testing/api-client/gradle/wrapper/gradle-wrapper.properties index 82dd18b204..eb1a55be0e 100644 --- a/tools/ingress-testing/api-client/gradle/wrapper/gradle-wrapper.properties +++ b/tools/ingress-testing/api-client/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=57dafb5c2622c6cc08b993c85b7c06956a2f53536432a30ead46166dbca0f1e9 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME