Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(*): update and add validation to lrs request models #61

Merged
merged 6 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ data class LearnersLRSRequest(

val dateOfBirth: LocalDate? = null,

// TODO: Validate gender
val gender: Int? = null,

@field:Size(max = 9)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ data class FindLearnerResponse(
var dateOfBirth: String = "",

@get:XmlElement(name = "Gender")
var gender: Int = 1,
var gender: String = "",

@get:XmlElement(name = "LastKnownPostCode")
var lastKnownPostCode: String = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.LearnerEventsLRSRequest
import java.time.LocalDate

class LearnerEventsRequest(
@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,

Expand All @@ -24,13 +24,13 @@ class LearnerEventsRequest(
val dateOfBirth: LocalDate?,

@SerializedName("gender")
val gender: Int?,
val gender: Gender?,
) {
fun extractFromRequest(): LearnerEventsLRSRequest = LearnerEventsLRSRequest(
givenName = givenName,
familyName = familyName,
uln = uln,
dateOfBirth = dateOfBirth,
gender = gender,
gender = gender?.value,
)
}
Original file line number Diff line number Diff line change
@@ -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.LearnersLRSRequest
import java.time.LocalDate
Expand All @@ -13,22 +11,18 @@ import java.time.LocalDate
// annotations support message = ''
data class LearnersRequest(
// 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")
Expand All @@ -38,7 +32,14 @@ data class LearnersRequest(
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),
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ class LearnersService(
): LearnersResponse {
val responseType = LRSResponseType.fromLrsResponseCode(response.responseCode)
val isPossibleMatch = responseType == LRSResponseType.POSSIBLE_MATCH
response.learners?.forEach { learner: Learner ->
val correctGender = when (learner.gender) {
"1" -> "MALE"
"2" -> "FEMALE"
"0" -> "NOT_KNOWN"
"9" -> "NOT_SPECIFIED"
else -> "Unknown"
}
learner.gender = correctGender
}

return LearnersResponse(
searchParameters = request,
responseType = responseType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -33,7 +35,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() {
"Darcie",
"Tucker",
LocalDate.parse("2024-01-01"),
1,
Gender.MALE,
"ABC123",
)

Expand All @@ -60,15 +62,15 @@ 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 =
uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.LearnersRequest(
"DarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcieDarcie",
"Tucker",
LocalDate.parse("2024-01-01"),
1,
Gender.MALE,
"CV49EE",
)

Expand All @@ -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.LearnersRequest(
"Darcie",
"TuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTuckerTucker",
LocalDate.parse("2024-01-01"),
1,
Gender.MALE,
"CV49EE",
)

Expand All @@ -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 learnersRequest =
uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.LearnersRequest(
"Darcie",
"Tucker",
LocalDate.parse("2024-01-01"),
4,
"CV49EE",
)

val findLearnerByDemographicsRequest =
"""{
"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")))
.bodyValue(learnersRequest)
.accept(MediaType.parseMediaType("application/json"))
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(findLearnerByDemographicsRequest)
.exchange()
.expectStatus()
.isBadRequest
Expand All @@ -173,7 +173,7 @@ class HmppsBoldLrsExceptionHandlerTest : IntegrationTestBase() {
"Darcie",
"Tucker",
LocalDate.parse("2024-01-01"),
2,
Gender.FEMALE,
"CV49EE",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.LearnerEventsRequest
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LearnerEventsResponse
Expand Down Expand Up @@ -206,6 +207,6 @@ class LearnerEventsResourceIntTest : IntegrationTestBase() {
"Some Family Name",
"1234567890",
null,
null,
Gender.MALE,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.Learner
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.Gender
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.request.LearnersRequest
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LearnersResponse
Expand All @@ -31,11 +32,14 @@ class LearnersResourceIntTest : IntegrationTestBase() {
"Some",
"Person",
LocalDate.parse("2024-01-01"),
1,
Gender.MALE,
"CV49EE",
)

private fun actualResponse(request: LearnersRequest = findLearnerByDemographicsRequest, expectedStatus: Int = 200): String? {
private fun actualResponse(
request: LearnersRequest = findLearnerByDemographicsRequest,
expectedStatus: Int = 200,
): String? {
val executedRequest = webTestClient.post()
.uri("/learners")
.headers(setAuthorisation(roles = listOf("ROLE_LEARNER_RECORDS_SEARCH__RO")))
Expand All @@ -58,6 +62,7 @@ class LearnersResourceIntTest : IntegrationTestBase() {
.expectBody()
.returnResult()
.responseBody?.toString(Charsets.UTF_8)

else ->
throw RuntimeException("Unimplemented Expected Status")
}
Expand Down Expand Up @@ -93,7 +98,7 @@ class LearnersResourceIntTest : IntegrationTestBase() {
dateOfAddressCapture = "2009-04-25",
dateOfBirth = "1976-08-16",
placeOfBirth = "Blean ",
gender = "2",
gender = "FEMALE",
emailAddress = "[email protected]",
scottishCandidateNumber = "845759406",
abilityToShare = "1",
Expand Down Expand Up @@ -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(
Expand All @@ -144,7 +149,7 @@ class LearnersResourceIntTest : IntegrationTestBase() {
dateOfAddressCapture = "2010-09-07",
dateOfBirth = "1995-06-28",
placeOfBirth = "Chard ",
gender = "2",
gender = "FEMALE",
emailAddress = "[email protected]",
scottishCandidateNumber = "820208781",
verificationType = "5",
Expand Down Expand Up @@ -172,7 +177,7 @@ class LearnersResourceIntTest : IntegrationTestBase() {
dateOfAddressCapture = "2010-09-07",
dateOfBirth = "1995-06-28",
placeOfBirth = "Chard ",
gender = "2",
gender = "FEMALE",
emailAddress = "[email protected]",
scottishCandidateNumber = "820208781",
verificationType = "5",
Expand All @@ -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,
Expand Down Expand Up @@ -236,7 +242,7 @@ class LearnersResourceIntTest : IntegrationTestBase() {
dateOfAddressCapture = "2008-07-13",
dateOfBirth = "1985-03-27",
placeOfBirth = "Whittlesey ",
gender = "1",
gender = "MALE",
emailAddress = "[email protected]",
scottishCandidateNumber = "145589606",
abilityToShare = "1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import uk.gov.justice.digital.hmpps.learnerrecordsapi.interfaces.LRSApiInterface
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.LearnerEventsRequest
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LRSResponseType
import uk.gov.justice.digital.hmpps.learnerrecordsapi.models.response.LearnerEventsResponse
Expand Down Expand Up @@ -61,7 +62,7 @@ class LearnerEventsServiceTest {
familyName = "test",
uln = "test",
dateOfBirth = LocalDate.of(1980, 1, 1),
gender = 1,
gender = Gender.MALE,
)
val expectedResult = LearnerEventsResponse(
searchParameters = body,
Expand Down Expand Up @@ -90,7 +91,7 @@ class LearnerEventsServiceTest {
familyName = "test",
uln = "test",
dateOfBirth = LocalDate.of(1980, 1, 1),
gender = 1,
gender = Gender.MALE,
)

val expectedException = LRSException(
Expand Down
Loading