Skip to content

Commit 441a5c7

Browse files
HMAI-306 - Add Prisons filter to /v1/persons/{encodedHmppsId}/reported-adjudications so can be used by kilco (#746)
* update controller and service to take filters * Fix path adjudications controller * update controller, service, and integration tests * fix error in hmppsid integration test --------- Co-authored-by: wcdkj <will.clark@digital.justice.gov.uk>
1 parent 2a824c7 commit 441a5c7

File tree

7 files changed

+87
-25
lines changed

7 files changed

+87
-25
lines changed

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/AdjudicationsController.kt

+13-5
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import io.swagger.v3.oas.annotations.media.Content
66
import io.swagger.v3.oas.annotations.media.Schema
77
import io.swagger.v3.oas.annotations.responses.ApiResponse
88
import io.swagger.v3.oas.annotations.tags.Tag
9+
import jakarta.validation.ValidationException
910
import org.springframework.beans.factory.annotation.Autowired
1011
import org.springframework.web.bind.annotation.GetMapping
1112
import org.springframework.web.bind.annotation.PathVariable
13+
import org.springframework.web.bind.annotation.RequestAttribute
1214
import org.springframework.web.bind.annotation.RequestMapping
1315
import org.springframework.web.bind.annotation.RequestParam
1416
import org.springframework.web.bind.annotation.RestController
1517
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.exception.EntityNotFoundException
16-
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.decodeUrlCharacters
1718
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Adjudication
1819
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
20+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
1921
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetAdjudicationsForPersonService
2022
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
2123
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.util.PaginatedResponse
@@ -28,26 +30,32 @@ class AdjudicationsController(
2830
@Autowired val auditService: AuditService,
2931
@Autowired val getAdjudicationsForPersonService: GetAdjudicationsForPersonService,
3032
) {
31-
@GetMapping("{encodedHmppsId}/reported-adjudications")
33+
@GetMapping("{hmppsId}/reported-adjudications")
3234
@Operation(
3335
summary = "Returns adjudications associated with a person, sorted by dateTimeOfIncident (newest first).",
36+
description = "<b>Applicable filters</b>: <ul><li>prisons</li></ul>",
3437
responses = [
3538
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "OK"),
3639
ApiResponse(responseCode = "404", description = "Failed to find adjudications for the person with the provided hmppsId.", content = [Content(schema = Schema(ref = "#/components/schemas/PersonNotFound"))]),
40+
ApiResponse(responseCode = "400", description = "Malformed hmppsId.", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),
3741
ApiResponse(responseCode = "500", content = [Content(schema = Schema(ref = "#/components/schemas/InternalServerError"))]),
3842
],
3943
)
4044
fun getPersonAdjudications(
41-
@Parameter(description = "A URL-encoded HMPPS identifier", example = "2008%2F0545166T") @PathVariable encodedHmppsId: String,
45+
@Parameter(description = "The HMPPS ID of the person") @PathVariable hmppsId: String,
4246
@Parameter(description = "The page number (starting from 1)", schema = Schema(minimum = "1")) @RequestParam(required = false, defaultValue = "1", name = "page") page: Int,
4347
@Parameter(description = "The maximum number of results for a page", schema = Schema(minimum = "1")) @RequestParam(required = false, defaultValue = "8", name = "perPage") perPage: Int,
48+
@RequestAttribute filters: ConsumerFilters?,
4449
): PaginatedResponse<Adjudication> {
45-
val hmppsId = encodedHmppsId.decodeUrlCharacters()
46-
val response = getAdjudicationsForPersonService.execute(hmppsId)
50+
val response = getAdjudicationsForPersonService.execute(hmppsId, filters)
4751

4852
if (response.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
4953
throw EntityNotFoundException("Could not find person with id: $hmppsId")
5054
}
55+
56+
if (response.hasError(UpstreamApiError.Type.BAD_REQUEST)) {
57+
throw ValidationException("Invalid or missing HMPPS ID: $hmppsId")
58+
}
5159
auditService.createEvent("GET_PERSON_ADJUDICATIONS", mapOf("hmppsId" to hmppsId))
5260
return response.data.paginateWith(page, perPage)
5361
}

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetAdjudicationsForPersonService.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ import org.springframework.stereotype.Service
55
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.AdjudicationsGateway
66
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Adjudication
77
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
8+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
89

910
@Service
1011
class GetAdjudicationsForPersonService(
1112
@Autowired val adjudicationsGateway: AdjudicationsGateway,
1213
@Autowired val getPersonService: GetPersonService,
1314
) {
14-
fun execute(hmppsId: String): Response<List<Adjudication>> {
15-
val personResponse = getPersonService.execute(hmppsId = hmppsId)
15+
fun execute(
16+
hmppsId: String,
17+
filters: ConsumerFilters? = null,
18+
): Response<List<Adjudication>> {
19+
val personResponse = getPersonService.getPersonWithPrisonFilter(hmppsId = hmppsId, filters = filters)
1620
val nomisNumber = personResponse.data?.identifiers?.nomisNumber
1721

1822
var adjudications: Response<List<Adjudication>> = Response(data = emptyList())

src/main/resources/globals.yml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ globals:
1717
- "/v1/persons/.*/name"
1818
- "/v1/persons/.*/cell-location"
1919
- "/v1/persons/.*/sentences"
20+
- "/v1/persons/.*/reported-adjudications"
2021
- "/v1/prison/prisoners"
2122
- "/v1/prison/prisoners/[^/]*$"
2223
- "/v1/prison/.*/prisoners/[^/]*/balances$"

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/controllers/v1/person/AdjudicationsControllerTest.kt

+39-9
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,37 @@ import org.springframework.test.web.servlet.MockMvc
1717
import org.springframework.web.reactive.function.client.WebClientResponseException
1818
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.helpers.IntegrationAPIMockMvc
1919
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Adjudication
20+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Identifiers
2021
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.IncidentDetailsDto
22+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Person
2123
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
2224
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi
2325
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
2426
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetAdjudicationsForPersonService
27+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPersonService
2528
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
26-
import java.net.URLEncoder
27-
import java.nio.charset.StandardCharsets
2829

2930
@WebMvcTest(controllers = [AdjudicationsController::class])
3031
@ActiveProfiles("test")
3132
internal class AdjudicationsControllerTest(
3233
@Autowired var springMockMvc: MockMvc,
3334
@MockitoBean val getAdjudicationsForPersonService: GetAdjudicationsForPersonService,
3435
@MockitoBean val auditService: AuditService,
36+
@MockitoBean val getPersonService: GetPersonService,
3537
) : DescribeSpec(
3638
{
37-
val hmppsId = "9999/11111A"
38-
val encodedHmppsId = URLEncoder.encode(hmppsId, StandardCharsets.UTF_8)
39-
val path = "/v1/persons/$encodedHmppsId/reported-adjudications"
39+
val hmppsId = "A1234AA"
40+
val path = "/v1/persons/$hmppsId/reported-adjudications"
4041
val mockMvc = IntegrationAPIMockMvc(springMockMvc)
42+
val filters = null
43+
val person = Person(firstName = "Qui-gon", lastName = "Jin", identifiers = Identifiers(nomisNumber = hmppsId))
4144

4245
describe("GET $path") {
4346
beforeTest {
4447
Mockito.reset(getAdjudicationsForPersonService)
4548
Mockito.reset(auditService)
46-
whenever(getAdjudicationsForPersonService.execute(hmppsId)).thenReturn(
49+
Mockito.reset(getPersonService)
50+
whenever(getAdjudicationsForPersonService.execute(hmppsId, filters)).thenReturn(
4751
Response(
4852
data =
4953
listOf(
@@ -56,10 +60,17 @@ internal class AdjudicationsControllerTest(
5660
),
5761
),
5862
)
63+
64+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId = hmppsId, filters = filters)).thenReturn(
65+
Response(
66+
data = person,
67+
errors = emptyList(),
68+
),
69+
)
5970
}
6071

6172
it("throws exception when no person found") {
62-
whenever(getAdjudicationsForPersonService.execute(hmppsId = "notfound")).thenReturn(
73+
whenever(getAdjudicationsForPersonService.execute(hmppsId = "notfound", filters)).thenReturn(
6374
Response(
6475
data = emptyList(),
6576
errors =
@@ -86,7 +97,7 @@ internal class AdjudicationsControllerTest(
8697
}
8798

8899
it("returns paginated adjudication results") {
89-
whenever(getAdjudicationsForPersonService.execute(hmppsId)).thenReturn(
100+
whenever(getAdjudicationsForPersonService.execute(hmppsId, filters)).thenReturn(
90101
Response(
91102
data =
92103
List(20) {
@@ -111,7 +122,7 @@ internal class AdjudicationsControllerTest(
111122
}
112123

113124
it("fails with the appropriate error when an upstream service is down") {
114-
whenever(getAdjudicationsForPersonService.execute(hmppsId)).doThrow(
125+
whenever(getAdjudicationsForPersonService.execute(hmppsId, filters)).doThrow(
115126
WebClientResponseException(500, "MockError", null, null, null, null),
116127
)
117128

@@ -124,6 +135,25 @@ internal class AdjudicationsControllerTest(
124135
),
125136
)
126137
}
138+
139+
it("returns a 400 Bad request status code when hmpps id invalid in the upstream API") {
140+
whenever(getAdjudicationsForPersonService.execute(hmppsId, filters)).thenReturn(
141+
Response(
142+
data = emptyList(),
143+
errors =
144+
listOf(
145+
UpstreamApiError(
146+
causedBy = UpstreamApi.ADJUDICATIONS,
147+
type = UpstreamApiError.Type.BAD_REQUEST,
148+
),
149+
),
150+
),
151+
)
152+
153+
val result = mockMvc.performAuthorised(path)
154+
155+
result.response.status.shouldBe(HttpStatus.BAD_REQUEST.value())
156+
}
127157
}
128158
},
129159
)

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/integration/HmppsIdIntegrationTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class HmppsIdIntegrationTest : IntegrationTestBase() {
122122

123123
@Test
124124
fun `gets the nomis, return a 404 when no prisons in filter`() {
125-
callApiWithCN("/v1/hmpps/id/nomis-number/by-hmpps-id/$nomsId", limitedPrisonsCn)
125+
callApiWithCN("/v1/hmpps/id/nomis-number/by-hmpps-id/$nomsId", noPrisonsCn)
126126
.andExpect(status().isNotFound)
127127
}
128128

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/integration/person/AdjudicationsIntegrationTest.kt

+18
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,22 @@ class AdjudicationsIntegrationTest : IntegrationTestBase() {
1313
.andExpect(status().isOk)
1414
.andExpect(content().json(getExpectedResponse("person-adjudications"), JsonCompareMode.STRICT))
1515
}
16+
17+
@Test
18+
fun `adjudications returns a 400 if the hmppsId is invalid`() {
19+
callApi("$basePath/$invalidNomsId/reported-adjudications")
20+
.andExpect(status().isBadRequest)
21+
}
22+
23+
@Test
24+
fun `return a 404 for person in wrong prison`() {
25+
callApiWithCN("$basePath/$nomsId/reported-adjudications", limitedPrisonsCn)
26+
.andExpect(status().isNotFound)
27+
}
28+
29+
@Test
30+
fun `return a 404 when no prisons in filter`() {
31+
callApiWithCN("$basePath/$nomsId/reported-adjudications", noPrisonsCn)
32+
.andExpect(status().isNotFound)
33+
}
1634
}

src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/services/GetAdjudicationsForPersonServiceTest.kt

+9-8
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,27 @@ internal class GetAdjudicationsForPersonServiceTest(
2828
private val getAdjudicationsForPersonService: GetAdjudicationsForPersonService,
2929
) : DescribeSpec(
3030
{
31-
val hmppsId = "1234/56789B"
31+
val hmppsId = "A1234AA"
3232
val prisonerNumber = "Z99999ZZ"
3333
val person = Person(firstName = "Qui-gon", lastName = "Jin", identifiers = Identifiers(nomisNumber = prisonerNumber))
3434
val adjudications = listOf(Adjudication(incidentDetails = IncidentDetailsDto(dateTimeOfIncident = "MockDate")))
35+
val filters = null
3536

3637
beforeEach {
3738
Mockito.reset(getPersonService)
3839
Mockito.reset(adjudicationsGateway)
3940

40-
whenever(getPersonService.execute(hmppsId = hmppsId)).thenReturn(Response(person))
41+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId = hmppsId, filters = filters)).thenReturn(Response(person))
4142
whenever(adjudicationsGateway.getReportedAdjudicationsForPerson(id = prisonerNumber)).thenReturn(Response(adjudications))
4243
}
4344

4445
it("performs a search according to hmpps Id") {
45-
getAdjudicationsForPersonService.execute(hmppsId)
46-
verify(getPersonService, VerificationModeFactory.times(1)).execute(hmppsId = hmppsId)
46+
getAdjudicationsForPersonService.execute(hmppsId, filters)
47+
verify(getPersonService, VerificationModeFactory.times(1)).getPersonWithPrisonFilter(hmppsId = hmppsId, filters = filters)
4748
}
4849

4950
it("should return a list of errors if person not found") {
50-
whenever(getPersonService.execute(hmppsId = "notfound")).thenReturn(
51+
whenever(getPersonService.getPersonWithPrisonFilter(hmppsId = "notfound", filters = filters)).thenReturn(
5152
Response(
5253
data = null,
5354
errors =
@@ -59,7 +60,7 @@ internal class GetAdjudicationsForPersonServiceTest(
5960
),
6061
),
6162
)
62-
val result = getAdjudicationsForPersonService.execute("notfound")
63+
val result = getAdjudicationsForPersonService.execute(hmppsId = "notfound", filters)
6364
result.data.shouldBe(emptyList())
6465
result.errors
6566
.first()
@@ -80,7 +81,7 @@ internal class GetAdjudicationsForPersonServiceTest(
8081
),
8182
),
8283
)
83-
val result = getAdjudicationsForPersonService.execute(hmppsId = hmppsId)
84+
val result = getAdjudicationsForPersonService.execute(hmppsId, filters)
8485
result.data.shouldBe(emptyList())
8586
result.errors
8687
.first()
@@ -89,7 +90,7 @@ internal class GetAdjudicationsForPersonServiceTest(
8990
}
9091

9192
it("should return adjudications from gateway") {
92-
val result = getAdjudicationsForPersonService.execute(hmppsId = hmppsId)
93+
val result = getAdjudicationsForPersonService.execute(hmppsId, filters)
9394
result.data
9495
.first()
9596
.incidentDetails

0 commit comments

Comments
 (0)