diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/request/FindLearnerByDemographicsLRSRequest.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/request/FindLearnerByDemographicsLRSRequest.kt index ab94916..cbd45c7 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/request/FindLearnerByDemographicsLRSRequest.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/request/FindLearnerByDemographicsLRSRequest.kt @@ -21,7 +21,6 @@ data class FindLearnerByDemographicsLRSRequest( val dateOfBirth: LocalDate? = null, - // TODO: Validate gender val gender: Int? = null, @field:Size(max = 9) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/response/FindLearnerResponse.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/response/FindLearnerResponse.kt index a98498b..9735526 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/response/FindLearnerResponse.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/lrsapi/response/FindLearnerResponse.kt @@ -1,5 +1,6 @@ package uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import javax.xml.bind.annotation.XmlElement import javax.xml.bind.annotation.XmlRootElement @@ -18,7 +19,7 @@ data class FindLearnerResponse( var dateOfBirth: String = "", @get:XmlElement(name = "Gender") - var gender: Int = 1, + var gender: Gender = Gender.NOT_SPECIFIED, @get:XmlElement(name = "LastKnownPostCode") var lastKnownPostCode: String = "", diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/FindLearnerByDemographicsRequest.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/FindLearnerByDemographicsRequest.kt index 5f373cd..a648de2 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/FindLearnerByDemographicsRequest.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/FindLearnerByDemographicsRequest.kt @@ -1,8 +1,6 @@ package uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request import com.google.gson.annotations.SerializedName -import jakarta.validation.constraints.Max -import jakarta.validation.constraints.Min import jakarta.validation.constraints.Pattern import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.request.FindLearnerByDemographicsLRSRequest import java.time.LocalDate @@ -13,22 +11,18 @@ import java.time.LocalDate // annotations support message = '' data class FindLearnerByDemographicsRequest( // Mandatory - @field:Pattern(regexp = "^[A-Za-z]{3,35}\$") + @field:Pattern(regexp = "^[A-Za-z' ,.-]{3,35}$") @SerializedName("givenName") val givenName: String, - @field:Pattern(regexp = "^[A-Za-z]{3,35}\$") + @field:Pattern(regexp = "^[A-Za-z' ,.-]{3,35}$") @SerializedName("familyName") val familyName: String, @SerializedName("dateOfBirth") val dateOfBirth: LocalDate, - // TODO: Validate gender - @SerializedName("gender") - @field:Min(0) - @field:Max(2) - val gender: Int, + val gender: Gender, @field:Pattern(regexp = "^[A-Z]{1,2}[0-9R][0-9A-Z]? ?[0-9][ABDEFGHJLNPQRSTUWXYZ]{2}|BFPO ?[0-9]{1,4}|([AC-FHKNPRTV-Y]\\d{2}|D6W)? ?[0-9AC-FHKNPRTV-Y]{4}\$") @SerializedName("lastKnownPostcode") @@ -38,7 +32,14 @@ data class FindLearnerByDemographicsRequest( givenName = givenName, familyName = familyName, dateOfBirth = dateOfBirth, - gender = gender, + gender = gender.value, lastKnownPostCode = lastKnownPostCode, ) } + +enum class Gender(val value: Int) { + MALE(1), + FEMALE(2), + NOT_KNOWN(0), + NOT_SPECIFIED(9), +} diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/GetPLRByULNRequest.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/GetPLRByULNRequest.kt index d046942..352ee49 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/GetPLRByULNRequest.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/models/request/GetPLRByULNRequest.kt @@ -2,20 +2,20 @@ package uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request import com.google.gson.annotations.SerializedName import jakarta.validation.constraints.Past -import jakarta.validation.constraints.Size +import jakarta.validation.constraints.Pattern import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.request.GetLearnerLearningEventsLRSRequest import java.time.LocalDate class GetPLRByULNRequest( - @field:Size(max = 35) + @field:Pattern(regexp = "^[A-Za-z' ,.-]{3,35}$") @SerializedName("givenName") val givenName: String, - @field:Size(max = 35) + @field:Pattern(regexp = "^[A-Za-z' ,.-]{3,35}$") @SerializedName("familyName") val familyName: String, - @field:Size(max = 10) + @field:Pattern(regexp = "^[0-9]{1,10}\$") @SerializedName("uln") val uln: String, @@ -24,13 +24,13 @@ class GetPLRByULNRequest( val dateOfBirth: LocalDate?, @SerializedName("gender") - val gender: Int?, + val gender: Gender, ) { fun extractFromRequest(): GetLearnerLearningEventsLRSRequest = GetLearnerLearningEventsLRSRequest( givenName = givenName, familyName = familyName, uln = uln, dateOfBirth = dateOfBirth, - gender = gender, + gender = gender.value, ) } diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/HmppsBoldLrsExceptionHandlerTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/HmppsBoldLrsExceptionHandlerTest.kt index 6c4156a..5fa97b7 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/HmppsBoldLrsExceptionHandlerTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/config/HmppsBoldLrsExceptionHandlerTest.kt @@ -8,6 +8,7 @@ import org.springframework.http.MediaType import uk.gov.justice.digital.hmpps.learnerrecordsapi.integration.IntegrationTestBase import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.LocalDateAdapter import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.ResponseTypeAdapter +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType import java.time.LocalDate @@ -16,6 +17,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { val gson = GsonBuilder() .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter().nullSafe()) .registerTypeAdapter(LRSResponseType::class.java, ResponseTypeAdapter().nullSafe()) + .disableHtmlEscaping() .create() @Test @@ -33,7 +35,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { "Darcie", "Tucker", LocalDate.parse("2024-01-01"), - 1, + Gender.MALE, "ABC123", ) @@ -60,7 +62,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { "Validation Failed", "Please correct the error and retry", "Validation(s) failed for [givenName]", - "Validation(s) failed for [givenName] with reason(s): [must match \"^[A-Za-z]{3,35}$\"]", + "Validation(s) failed for [givenName] with reason(s): [must match \"^[A-Za-z' ,.-]{3,35}$\"]", ) val findLearnerByDemographicsRequest = @@ -68,7 +70,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { "DarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcie", "Tucker", LocalDate.parse("2024-01-01"), - 1, + Gender.MALE, "CV49EE", ) @@ -95,15 +97,14 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { "Validation Failed", "Please correct the error and retry", "Validation(s) failed for [familyName]", - "Validation(s) failed for [familyName] with reason(s): [must match \"^[A-Za-z]{3,35}$\"]", + "Validation(s) failed for [familyName] with reason(s): [must match \"^[A-Za-z' ,.-]{3,35}\$\"]", ) - val findLearnerByDemographicsRequest = uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.FindLearnerByDemographicsRequest( "Darcie", "TuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTucker", LocalDate.parse("2024-01-01"), - 1, + Gender.MALE, "CV49EE", ) @@ -127,26 +128,25 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { fun `should return validation errors when user gender is invalid`() { val expectedResponse = HmppsBoldLrsExceptionHandler.ErrorResponse( HttpStatus.BAD_REQUEST, - "Validation Failed", - "Please correct the error and retry", - "Validation(s) failed for [gender]", - "Validation(s) failed for [gender] with reason(s): [must be less than or equal to 2]", + "Unreadable HTTP message", + "Unreadable HTTP message", + "JSON parse error: Cannot deserialize value of type `uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender` from String \"TESTINGENUM\": not one of the values accepted for Enum class: [NOT_SPECIFIED, MALE, NOT_KNOWN, FEMALE]", + "Unreadable HTTP message", ) val findLearnerByDemographicsRequest = - uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.FindLearnerByDemographicsRequest( - "Darcie", - "Tucker", - LocalDate.parse("2024-01-01"), - 4, - "CV49EE", - ) - + """{ + "givenName":"Darcie", + "familyName": "Tucker", + "dateOfBirth": "2024-01-01", + "gender": "TESTINGENUM", + "postcode": "CV49EE" + }""" val actualResponse = webTestClient.post() .uri("/learners") .headers(setAuthorisation(roles = listOf("ROLE_LEARNER_RECORDS_SEARCH__RO"))) + .contentType(MediaType.APPLICATION_JSON) .bodyValue(findLearnerByDemographicsRequest) - .accept(MediaType.parseMediaType("application/json")) .exchange() .expectStatus() .isBadRequest @@ -173,7 +173,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() { "Darcie", "Tucker", LocalDate.parse("2024-01-01"), - 2, + Gender.FEMALE, "CV49EE", ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/LearnersResourceIntTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/LearnersResourceIntTest.kt index c00671c..c42dee9 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/LearnersResourceIntTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/LearnersResourceIntTest.kt @@ -11,6 +11,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.LocalD import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.ResponseTypeAdapter import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.Learner import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.FindLearnerByDemographicsRequest +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.FindLearnerByDemographicsResponse import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType import java.time.LocalDate @@ -31,11 +32,14 @@ class LearnersResourceIntTest : IntegrationTestBase() { "Some", "Person", LocalDate.parse("2024-01-01"), - 1, + Gender.MALE, "CV49EE", ) - private fun actualResponse(request: FindLearnerByDemographicsRequest = findLearnerByDemographicsRequest, expectedStatus: Int = 200): String? { + private fun actualResponse( + request: FindLearnerByDemographicsRequest = findLearnerByDemographicsRequest, + expectedStatus: Int = 200, + ): String? { val executedRequest = webTestClient.post() .uri("/learners") .headers(setAuthorisation(roles = listOf("ROLE_LEARNER_RECORDS_SEARCH__RO"))) @@ -58,6 +62,7 @@ class LearnersResourceIntTest : IntegrationTestBase() { .expectBody() .returnResult() .responseBody?.toString(Charsets.UTF_8) + else -> throw RuntimeException("Unimplemented Expected Status") } @@ -122,7 +127,7 @@ class LearnersResourceIntTest : IntegrationTestBase() { familyName = "Cheng", lastKnownPostCode = "NE26 3ND", dateOfBirth = LocalDate.parse("1995-06-27"), - gender = 2, + gender = Gender.FEMALE, ) val expectedPossibleMatchLearners = mutableListOf( @@ -189,6 +194,7 @@ class LearnersResourceIntTest : IntegrationTestBase() { responseType = LRSResponseType.POSSIBLE_MATCH, mismatchedFields = mutableMapOf( ("dateOfBirth" to mutableListOf("1995-06-28", "1995-06-28")), + ("gender" to mutableListOf("2", "2")), ("lastKnownPostCode" to mutableListOf("SO40 4JX")), ), matchedLearners = expectedPossibleMatchLearners, diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/PLRResourceIntTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/PLRResourceIntTest.kt index bf0e340..9dbce72 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/PLRResourceIntTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/integration/PLRResourceIntTest.kt @@ -10,6 +10,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.integration.wiremock.LRSAp import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.LocalDateAdapter import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.gsonadapters.ResponseTypeAdapter import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.LearningEvent +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.GetPLRByULNRequest import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.GetPLRByULNResponse import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType @@ -206,6 +207,6 @@ class PLRResourceIntTest : IntegrationTestBase() { "Some Family Name", "1234567890", null, - null, + Gender.MALE, ) } diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/LRSServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/LRSServiceTest.kt index d540712..83b152f 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/LRSServiceTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/LRSServiceTest.kt @@ -26,6 +26,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.Lea import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.MIAPAPIException import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.exceptions.LRSException import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.FindLearnerByDemographicsRequest +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.FindLearnerByDemographicsResponse import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType import java.io.InputStreamReader @@ -64,7 +65,7 @@ class LRSServiceTest { givenName = "Some", familyName = "Person", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, lastKnownPostCode = "ABCDEF", ) @@ -94,7 +95,7 @@ class LRSServiceTest { familyName = "Person", givenName = "Some", dateOfBirth = LocalDate.of(1980, 1, 1).toString(), - gender = 1, + Gender.MALE, lastKnownPostCode = "ABCDEF", learners = listOf(Learner(givenName = "Some")), ) @@ -107,7 +108,7 @@ class LRSServiceTest { givenName = "Some", familyName = "Person", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, lastKnownPostCode = "ABCDEF", ) @@ -137,7 +138,7 @@ class LRSServiceTest { familyName = "Person", givenName = "Some", dateOfBirth = LocalDate.of(1980, 1, 1).toString(), - gender = 1, + Gender.MALE, lastKnownPostCode = "ABCDEF", learners = listOf(Learner(givenName = "Some"), Learner(givenName = "Mismatch")), ) @@ -150,7 +151,7 @@ class LRSServiceTest { givenName = "Some", familyName = "Person", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, lastKnownPostCode = "ABCDEF", ) @@ -181,7 +182,7 @@ class LRSServiceTest { givenName = "Some", familyName = "Person", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, lastKnownPostCode = "ABCDEF", ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/PLRServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/PLRServiceTest.kt index c315753..82c5cdf 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/PLRServiceTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/learnerrecordsapi/service/PLRServiceTest.kt @@ -21,6 +21,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.interfaces.LRSApiServiceIn import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.LearningEventsEnvelope import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.MIAPAPIException import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.lrsapi.response.exceptions.LRSException +import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.GetPLRByULNRequest import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.GetPLRByULNResponse import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType @@ -61,7 +62,7 @@ class PLRServiceTest { familyName = "test", uln = "test", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, ) val expectedResult = GetPLRByULNResponse( searchParameters = body, @@ -90,7 +91,7 @@ class PLRServiceTest { familyName = "test", uln = "test", dateOfBirth = LocalDate.of(1980, 1, 1), - gender = 1, + gender = Gender.MALE, ) val expectedException = LRSException(