Skip to content

Commit

Permalink
CDPS-1086: Moving medical diet, allergy code over from hmpps-prison-p…
Browse files Browse the repository at this point in the history
…erson-api
  • Loading branch information
brightonsbox committed Jan 17, 2025
1 parent 8debbac commit bcdcef2
Show file tree
Hide file tree
Showing 89 changed files with 2,726 additions and 486 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Docker Repository on Quay](https://img.shields.io/badge/quay.io-repository-2496ED.svg?logo=docker)](https://quay.io/repository/hmpps/hmpps-health-and-medication-api)
[![API docs](https://img.shields.io/badge/API_docs_-view-85EA2D.svg?logo=swagger)](https://health-and-medication-api-dev.prison.service.justice.gov.uk/swagger-ui/index.html)

This is a Spring Boot service, written in Kotlin, which owns a subset of data about a person in prison (migrated from NOMIS).
This is a Spring Boot service, written in Kotlin, which owns health and medication data about a person in prison.

## Contents

Expand Down
17 changes: 10 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id("uk.gov.justice.hmpps.gradle-spring-boot") version "6.1.0"
id("uk.gov.justice.hmpps.gradle-spring-boot") version "6.0.9"
kotlin("plugin.spring") version "2.0.21"
kotlin("plugin.jpa") version "2.0.21"
jacoco
Expand All @@ -13,23 +13,26 @@ configurations {
dependencies {

// Spring Boot
implementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter:1.1.0")
implementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter:1.0.8")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")

// OpenAPI
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")

// UUIDs
implementation("com.fasterxml.uuid:java-uuid-generator:5.1.0")

// Database
runtimeOnly("com.zaxxer:HikariCP")
runtimeOnly("org.flywaydb:flyway-database-postgresql")
runtimeOnly("org.postgresql:postgresql")

// Test
testImplementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter-test:1.1.0")
testImplementation("org.testcontainers:junit-jupiter:1.20.3")
testImplementation("org.testcontainers:postgresql:1.20.3")
testImplementation("org.wiremock:wiremock-standalone:3.9.2")
testImplementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter-test:1.1.1")
testImplementation("org.testcontainers:junit-jupiter:1.20.4")
testImplementation("org.testcontainers:postgresql:1.20.4")
testImplementation("org.wiremock:wiremock-standalone:3.10.0")
testImplementation("io.swagger.parser.v3:swagger-parser:2.1.24") {
exclude(group = "io.swagger.core.v3")
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
4 changes: 4 additions & 0 deletions helm_deploy/hmpps-health-and-medication-api/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ generic-service:
# [name of environment variable as seen by app]: [key of kubernetes secret to load]

namespace_secrets:
hmpps-health-and-medication-api:
CLIENT_ID: "CLIENT_ID"
CLIENT_SECRET: "CLIENT_SECRET"

application-insights:
APPLICATIONINSIGHTS_CONNECTION_STRING: "APPLICATIONINSIGHTS_CONNECTION_STRING"

Expand Down
3 changes: 2 additions & 1 deletion helm_deploy/values-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ generic-service:

env:
APPLICATIONINSIGHTS_CONFIGURATION_FILE: "applicationinsights.dev.json"
HMPPS_AUTH_URL: "https://sign-in-dev.hmpps.service.justice.gov.uk/auth"
API_HMPPS_AUTH_BASE_URL: "https://sign-in-dev.hmpps.service.justice.gov.uk/auth"
API_PRISONER_SEARCH_BASE_URL: "https://prisoner-search-dev.prison.service.justice.gov.uk"

scheduledDowntime:
enabled: true
Expand Down
3 changes: 2 additions & 1 deletion helm_deploy/values-preprod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ generic-service:

env:
APPLICATIONINSIGHTS_CONFIGURATION_FILE: "applicationinsights.dev.json"
HMPPS_AUTH_URL: "https://sign-in-preprod.hmpps.service.justice.gov.uk/auth"
API_HMPPS_AUTH_BASE_URL: "https://sign-in-preprod.hmpps.service.justice.gov.uk/auth"
API_PRISONER_SEARCH_BASE_URL: "https://prisoner-search-preprod.prison.service.justice.gov.uk"

# CloudPlatform AlertManager receiver to route prometheus alerts to slack
# See https://user-guide.cloud-platform.service.justice.gov.uk/documentation/monitoring-an-app/how-to-create-alarms.html#creating-your-own-custom-alerts
Expand Down
3 changes: 2 additions & 1 deletion helm_deploy/values-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ generic-service:
host: health-and-medication-api.hmpps.service.justice.gov.uk

env:
HMPPS_AUTH_URL: "https://sign-in.hmpps.service.justice.gov.uk/auth"
API_HMPPS_AUTH_BASE_URL: "https://sign-in.hmpps.service.justice.gov.uk/auth"
API_PRISONER_SEARCH_BASE_URL: "https://prisoner-search.prison.service.justice.gov.uk"

# CloudPlatform AlertManager receiver to route prometheus alerts to slack
# See https://user-guide.cloud-platform.service.justice.gov.uk/documentation/monitoring-an-app/how-to-create-alarms.html#creating-your-own-custom-alerts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package uk.gov.justice.digital.hmpps.healthandmedicationapi
package uk.gov.justice.digital.hmpps.healthandmedication

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

const val SYSTEM_USERNAME = "HEALTH_AND_MEDICATION_API"

@SpringBootApplication
class HealthAndMedicationApi

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package uk.gov.justice.digital.hmpps.healthandmedication.annotation

import jakarta.validation.Constraint
import jakarta.validation.Payload
import uk.gov.justice.digital.hmpps.healthandmedication.validator.NullishRangeValidator
import kotlin.reflect.KClass

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = [NullishRangeValidator::class])
annotation class NullishRange(
val min: Int,
val max: Int,
val message: String = "The value must be within the specified range, null or Undefined.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package uk.gov.justice.digital.hmpps.healthandmedication.annotation

import jakarta.validation.Constraint
import jakarta.validation.Payload
import uk.gov.justice.digital.hmpps.healthandmedication.validator.NullishReferenceDataCodeValidator
import kotlin.reflect.KClass

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = [NullishReferenceDataCodeValidator::class])
annotation class NullishReferenceDataCode(
val domains: Array<String> = [],
val allowNull: Boolean = true,
val message: String = "The value must be a reference domain code id of the correct domain, null, or Undefined.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package uk.gov.justice.digital.hmpps.healthandmedication.annotation

import jakarta.validation.Constraint
import jakarta.validation.Payload
import uk.gov.justice.digital.hmpps.healthandmedication.validator.NullishReferenceDataCodeListValidator
import kotlin.reflect.KClass

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = [NullishReferenceDataCodeListValidator::class])
annotation class NullishReferenceDataCodeList(
val domains: Array<String> = [],
val message: String = "The value must be a a list of domain codes of the correct domain, an empty list, or Undefined.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package uk.gov.justice.digital.hmpps.healthandmedication.annotation

import jakarta.validation.Constraint
import jakarta.validation.Payload
import uk.gov.justice.digital.hmpps.healthandmedication.validator.NullishShoeSizeValidator
import kotlin.reflect.KClass

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = [NullishShoeSizeValidator::class])
annotation class NullishShoeSize(
val min: String,
val max: String,
val message: String = "The value must be a whole or half shoe size within the specified range, null or Undefined.",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = [],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package uk.gov.justice.digital.hmpps.healthandmedication.client.prisonersearch

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException.NotFound
import uk.gov.justice.digital.hmpps.healthandmedication.client.prisonersearch.dto.PrisonerDto
import uk.gov.justice.digital.hmpps.healthandmedication.config.DownstreamServiceException

@Component
class PrisonerSearchClient(@Qualifier("prisonerSearchWebClient") private val webClient: WebClient) {
fun getPrisoner(prisonerNumber: String): PrisonerDto? = try {
webClient
.get()
.uri("/prisoner/{prisonerNumber}", prisonerNumber)
.retrieve()
.bodyToMono(PrisonerDto::class.java)
.block()
} catch (e: NotFound) {
null
} catch (e: Exception) {
throw DownstreamServiceException("Get prisoner request failed", e)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package uk.gov.justice.digital.hmpps.healthandmedication.client.prisonersearch.dto

data class PrisonerDto(
val prisonerNumber: String,
val prisonId: String? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package uk.gov.justice.digital.hmpps.healthandmedication.config

import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Clock
import java.time.ZoneId

@Configuration
class ClockConfiguration(
@Value("\${spring.jackson.time-zone}") private val timeZone: String,
) {
@Bean
fun clock(): Clock? = Clock.system(ZoneId.of(timeZone))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package uk.gov.justice.digital.hmpps.healthandmedication.config

import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer
import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.ZoneId
import java.time.format.DateTimeFormatter

@Configuration
class CustomisedJacksonObjectMapper(
@Value("\${spring.jackson.time-zone}") private val timeZone: String,
@Value("\${spring.jackson.date-format}") private val zonedDateTimeFormat: String,
) {
@Bean
fun serialiser() = Jackson2ObjectMapperBuilderCustomizer {
val zoneId = ZoneId.of(timeZone)
val naiveDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(zoneId)
val naiveDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(zoneId)
val zonedDateTimeFormatter = DateTimeFormatter.ofPattern(zonedDateTimeFormat).withZone(zoneId)

it.serializers(
LocalDateSerializer(naiveDateFormatter),
LocalDateTimeSerializer(naiveDateTimeFormatter),
ZonedDateTimeSerializer(zonedDateTimeFormatter),
)
}
}
Loading

0 comments on commit bcdcef2

Please sign in to comment.