Skip to content

Commit 6f6e753

Browse files
authored
Merge branch 'main' into HMAI-305-filter
2 parents 481754c + 441a5c7 commit 6f6e753

28 files changed

+461
-268
lines changed

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

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.NomisNumber
1717
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
1818
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
1919
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetHmppsIdService
20+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.GetPersonService
2021
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
2122

2223
@RestController
@@ -25,6 +26,7 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditS
2526
class HmppsIdController(
2627
@Autowired val getHmppsIdService: GetHmppsIdService,
2728
@Autowired val auditService: AuditService,
29+
@Autowired val getPersonService: GetPersonService,
2830
) {
2931
@GetMapping("nomis-number/{nomisNumber}", "by-nomis-number/{nomisNumber}")
3032
@Operation(
@@ -58,7 +60,9 @@ class HmppsIdController(
5860
@GetMapping("nomis-number/by-hmpps-id/{hmppsId}")
5961
@Operation(
6062
summary = "Return nomis number for a given HMPPS Id",
61-
description = """Accepts a HMPPS Id (hmppsId) and looks up the corresponding nomis number.
63+
description = """
64+
Accepts a HMPPS Id (hmppsId) and looks up the corresponding nomis number.<br>
65+
<b>Applicable filters</b>: <ul><li>prisons</li></ul>
6266
""",
6367
responses = [
6468
ApiResponse(responseCode = "200", useReturnTypeSchema = true),
@@ -68,8 +72,9 @@ class HmppsIdController(
6872
)
6973
fun getNomisNumberByHMPPSID(
7074
@PathVariable hmppsId: String,
75+
@RequestAttribute filters: ConsumerFilters?,
7176
): DataResponse<NomisNumber?> {
72-
val response = getHmppsIdService.getNomisNumber(hmppsId)
77+
val response = getPersonService.getNomisNumberWithPrisonFilter(hmppsId, filters)
7378
if (response.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
7479
throw EntityNotFoundException("Could not find nomis number for HMPPS ID: $hmppsId")
7580
}

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

+14-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.RestController
1416
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.exception.EntityNotFoundException
15-
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.decodeUrlCharacters
1617
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Address
1718
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.DataResponse
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.GetAddressesForPersonService
2022
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.internal.AuditService
2123

@@ -26,26 +28,33 @@ class AddressController(
2628
@Autowired val auditService: AuditService,
2729
@Autowired val getAddressesForPersonService: GetAddressesForPersonService,
2830
) {
29-
@GetMapping("{encodedHmppsId}/addresses")
31+
@GetMapping("{hmppsId}/addresses")
3032
@Operation(
3133
summary = "Returns addresses associated with a person, ordered by startDate.",
34+
description = "<b>Applicable filters</b>: <ul><li>prisons</li></ul>",
3235
responses = [
3336
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "Successfully found a person with the provided HMPPS ID."),
37+
ApiResponse(responseCode = "400", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),
3438
ApiResponse(responseCode = "404", content = [Content(schema = Schema(ref = "#/components/schemas/PersonNotFound"))]),
3539
ApiResponse(responseCode = "500", content = [Content(schema = Schema(ref = "#/components/schemas/InternalServerError"))]),
3640
],
3741
)
3842
fun getPersonAddresses(
39-
@Parameter(description = "A URL-encoded HMPPS identifier", example = "2008%2F0545166T") @PathVariable encodedHmppsId: String,
43+
@Parameter(description = "The HMPPS ID of the person", example = "G2996UX") @PathVariable hmppsId: String,
44+
@RequestAttribute filters: ConsumerFilters?,
4045
): DataResponse<List<Address>> {
41-
val hmppsId = encodedHmppsId.decodeUrlCharacters()
42-
val response = getAddressesForPersonService.execute(hmppsId)
46+
val response = getAddressesForPersonService.execute(hmppsId, filters)
47+
48+
if (response.hasError(UpstreamApiError.Type.BAD_REQUEST)) {
49+
throw ValidationException("Invalid id: $hmppsId")
50+
}
4351

4452
if (response.hasError(UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
4553
throw EntityNotFoundException("Could not find person with id: $hmppsId")
4654
}
4755

4856
auditService.createEvent("GET_PERSON_ADDRESS", mapOf("hmppsId" to hmppsId))
57+
4958
return DataResponse(response.data)
5059
}
5160
}

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/controllers/v1/person/AlertsController.kt

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AlertsController(
3535
@GetMapping("/persons/{hmppsId}/alerts")
3636
@Operation(
3737
summary = "Returns alerts associated with a person, sorted by dateCreated (newest first).",
38+
description = "<b>Applicable filters</b>: <ul><li>prisons</li></ul>",
3839
responses = [
3940
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "Successfully found alerts for a person with the provided HMPPS ID."),
4041
ApiResponse(responseCode = "400", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),

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

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class PersonController(
147147
@GetMapping("{hmppsId}/name")
148148
@Operation(
149149
summary = "Returns a person's name",
150+
description = "<b>Applicable filters</b>: <ul><li>prisons</li></ul>",
150151
responses = [
151152
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "Successfully found a person with the provided HMPPS ID."),
152153
ApiResponse(responseCode = "400", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,31 @@ class SentencesController(
3636
@Autowired val getLatestSentenceKeyDatesAndAdjustmentsForPersonService: GetLatestSentenceKeyDatesAndAdjustmentsForPersonService,
3737
@Autowired val auditService: AuditService,
3838
) {
39-
@GetMapping("{encodedHmppsId}/sentences")
39+
@GetMapping("{hmppsId}/sentences")
4040
@Operation(
4141
summary = "Returns sentences associated with a person, sorted by dateOfSentencing (newest first).",
42+
description = "<b>Applicable filters</b>: <ul><li>prisons</li></ul>",
4243
responses = [
4344
ApiResponse(responseCode = "200", useReturnTypeSchema = true, description = "Successfully found sentences for a person with the provided HMPPS ID."),
45+
ApiResponse(responseCode = "400", content = [Content(schema = Schema(ref = "#/components/schemas/BadRequest"))]),
4446
ApiResponse(responseCode = "404", content = [Content(schema = Schema(ref = "#/components/schemas/PersonNotFound"))]),
4547
ApiResponse(responseCode = "500", content = [Content(schema = Schema(ref = "#/components/schemas/InternalServerError"))]),
4648
],
4749
)
4850
fun getPersonSentences(
49-
@Parameter(description = "A URL-encoded HMPPS identifier", example = "2008%2F0545166T") @PathVariable encodedHmppsId: String,
51+
@Parameter(description = "The HMPPS ID of the person") @PathVariable hmppsId: String,
5052
@Parameter(description = "The page number (starting from 1)", schema = Schema(minimum = "1")) @RequestParam(required = false, defaultValue = "1", name = "page") page: Int,
5153
@Parameter(description = "The maximum number of results for a page", schema = Schema(minimum = "1")) @RequestParam(required = false, defaultValue = "10", name = "perPage") perPage: Int,
54+
@RequestAttribute filters: ConsumerFilters?,
5255
): PaginatedResponse<Sentence> {
53-
val hmppsId = encodedHmppsId.decodeUrlCharacters()
54-
val response = getSentencesForPersonService.execute(hmppsId)
56+
val response = getSentencesForPersonService.execute(hmppsId, filters)
5557

5658
if (response.hasErrorCausedBy(causedBy = UpstreamApi.NOMIS, type = UpstreamApiError.Type.ENTITY_NOT_FOUND)) {
5759
throw EntityNotFoundException("Could not find person with id: $hmppsId")
5860
}
61+
if (response.hasError(UpstreamApiError.Type.BAD_REQUEST)) {
62+
throw ValidationException("Invalid HMPPS ID: $hmppsId")
63+
}
5964

6065
auditService.createEvent("GET_PERSON_SENTENCES", mapOf("hmppsId" to hmppsId))
6166
return response.data.paginateWith(page, perPage)
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,35 @@
11
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps
22

3-
import com.fasterxml.jackson.annotation.JsonProperty
3+
import io.swagger.v3.oas.annotations.media.Schema
44

55
data class PrisonerContactRestrictions(
6-
var prisonerContactRestrictions: List<PrisonerContactRestriction>? = emptyList(),
7-
var contactGlobalRestrictions: List<ContactGlobalRestriction>? = emptyList(),
6+
@Schema(description = "Relationship specific restrictions")
7+
var prisonerContactRestrictions: List<ContactRestriction>,
8+
@Schema(description = "Global (estate-wide) restrictions for the contact")
9+
var contactGlobalRestrictions: List<ContactRestriction>,
810
)
911

10-
data class PrisonerContactRestriction(
11-
val prisonerContactRestrictionId: Long,
12-
val prisonerContactId: Long,
13-
val contactId: Long,
14-
val prisonerNumber: String,
12+
data class ContactRestriction(
13+
@Schema(description = "The restriction code", examples = ["CC", "BAN", "CHILD", "CLOSED", "RESTRICTED", "DIHCON", "NONCON"])
1514
val restrictionType: String,
15+
@Schema(description = "The description of the restriction type", example = "Banned")
1616
val restrictionTypeDescription: String,
17+
@Schema(description = "Restriction created date", example = "2024-01-01")
1718
val startDate: String,
19+
@Schema(description = "Restriction expiry date", example = "2024-01-01")
1820
val expiryDate: String,
21+
@Schema(description = "Comments for the restriction", example = "N/A")
1922
val comments: String,
23+
@Schema(description = "The username of either the person who created the restriction or the last person to update it if it has been modified", example = "admin")
2024
val enteredByUsername: String,
25+
@Schema(description = "The display name of either the person who created the restriction or the last person to update it if it has been modified", example = "John Smith")
2126
val enteredByDisplayName: String,
27+
@Schema(description = "User who created the entry", example = "admin")
2228
val createdBy: String,
29+
@Schema(description = "Timestamp when the entry was created", example = "2023-09-23T10:15:30")
2330
val createdTime: String,
31+
@Schema(description = "User who updated the entry", example = "admin")
2432
val updatedBy: String,
25-
val updatedTime: String,
26-
)
27-
28-
data class ContactGlobalRestriction(
29-
@JsonProperty("contactRestrictionId")
30-
val contactRestrictionId: Long,
31-
@JsonProperty("contactId")
32-
val contactId: Long,
33-
@JsonProperty("restrictionType")
34-
val restrictionType: String,
35-
@JsonProperty("restrictionTypeDescription")
36-
val restrictionTypeDescription: String,
37-
@JsonProperty("startDate")
38-
val startDate: String,
39-
@JsonProperty("expiryDate")
40-
val expiryDate: String,
41-
@JsonProperty("comments")
42-
val comments: String,
43-
@JsonProperty("enteredByUsername")
44-
val enteredByUsername: String,
45-
@JsonProperty("enteredByDisplayName")
46-
val enteredByDisplayName: String,
47-
@JsonProperty("createdBy")
48-
val createdBy: String,
49-
@JsonProperty("createdTime")
50-
val createdTime: String,
51-
@JsonProperty("updatedBy")
52-
val updatedBy: String,
53-
@JsonProperty("updatedTime")
33+
@Schema(description = "Timestamp when the entry was updated", example = "2023-09-23T10:15:30")
5434
val updatedTime: String,
5535
)

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/models/personalRelationships/PRPrisonerContactRestrictions.kt

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.personalRelationships
22

33
import com.fasterxml.jackson.annotation.JsonProperty
4-
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.ContactGlobalRestriction
5-
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.PrisonerContactRestriction
4+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.ContactRestriction
65

76
data class PRPrisonerContactRestrictions(
8-
var prisonerContactRestrictions: List<PRPrisonerContactRestriction>? = emptyList(),
9-
var contactGlobalRestrictions: List<PRContactGlobalRestriction>? = emptyList(),
7+
val prisonerContactRestrictions: List<PRPrisonerContactRestriction>? = emptyList(),
8+
val contactGlobalRestrictions: List<PRContactGlobalRestriction>? = emptyList(),
109
)
1110

1211
data class PRPrisonerContactRestriction(
@@ -26,12 +25,8 @@ data class PRPrisonerContactRestriction(
2625
val updatedBy: String,
2726
val updatedTime: String,
2827
) {
29-
fun toPrisonerContactRestriction() =
30-
PrisonerContactRestriction(
31-
prisonerContactRestrictionId = this.prisonerContactRestrictionId,
32-
prisonerContactId = this.prisonerContactId,
33-
contactId = this.contactId,
34-
prisonerNumber = this.prisonerNumber,
28+
fun toContactRestriction() =
29+
ContactRestriction(
3530
restrictionType = this.restrictionType,
3631
restrictionTypeDescription = this.restrictionTypeDescription,
3732
startDate = this.startDate,
@@ -74,10 +69,8 @@ data class PRContactGlobalRestriction(
7469
@JsonProperty("updatedTime")
7570
val updatedTime: String,
7671
) {
77-
fun toContactGlobalRestriction() =
78-
ContactGlobalRestriction(
79-
contactRestrictionId = this.contactRestrictionId,
80-
contactId = this.contactId,
72+
fun toContactRestriction() =
73+
ContactRestriction(
8174
restrictionType = this.restrictionType,
8275
restrictionTypeDescription = this.restrictionTypeDescription,
8376
startDate = this.startDate,

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

+7-6
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.ProbationOffend
77
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Address
88
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
99
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
10+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.roleconfig.ConsumerFilters
1011

1112
@Service
1213
class GetAddressesForPersonService(
1314
@Autowired val nomisGateway: NomisGateway,
1415
@Autowired val getPersonService: GetPersonService,
1516
@Autowired val probationOffenderSearchGateway: ProbationOffenderSearchGateway,
1617
) {
17-
fun execute(hmppsId: String): Response<List<Address>> {
18-
val personResponse = getPersonService.execute(hmppsId = hmppsId)
18+
fun execute(
19+
hmppsId: String,
20+
filters: ConsumerFilters?,
21+
): Response<List<Address>> {
22+
val personResponse = getPersonService.getNomisNumberWithPrisonFilter(hmppsId = hmppsId, filters)
1923
if (personResponse.errors.isNotEmpty()) {
2024
return Response(data = emptyList(), errors = personResponse.errors)
2125
}
@@ -25,10 +29,7 @@ class GetAddressesForPersonService(
2529
return Response(data = emptyList(), errors = addressesFromDelius.errors)
2630
}
2731

28-
val nomisNumber = personResponse.data?.identifiers?.nomisNumber
29-
if (nomisNumber == null) {
30-
return addressesFromDelius
31-
}
32+
val nomisNumber = personResponse.data?.nomisNumber ?: return addressesFromDelius
3233

3334
val addressesFromNomis = nomisGateway.getAddressesForPerson(id = nomisNumber)
3435
if (hasErrorOtherThanEntityNotFound(addressesFromNomis)) {

0 commit comments

Comments
 (0)