Skip to content

Commit

Permalink
Add CAS1 CRU Management Area to User API Model
Browse files Browse the repository at this point in the history
This commit adds CRU Management Area fields to the ApprovedPremisesUser API Model to support:

* Determining which CRU Management Area the user is in (when retrieved via /profile/v2)
* Logic to determine/set/get override configuration for the user management page

This commit is quite large because i had fix existing test data where entries in the users table were created for CAS1 testing and the CRU Management Area was not set, something which wouldn’t be the case in production (it’s logically mandatory for CAS1 users)
  • Loading branch information
davidatkinsuk committed Sep 24, 2024
1 parent 296f884 commit a93b17c
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ data class UserEntity(
) {
fun hasRole(userRole: UserRole) = roles.any { it.role == userRole }
fun hasAnyRole(vararg userRoles: UserRole) = userRoles.any(::hasRole)
fun hasAnyRole(userRoles: List<UserRole>) = userRoles.any(::hasRole)
fun hasQualification(userQualification: UserQualification) =
qualifications.any { it.qualification === userQualification }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package uk.gov.justice.digital.hmpps.approvedpremisesapi.transformer
import org.springframework.stereotype.Component
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUser
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUserRole
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NamedId
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ProfileResponse
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ServiceName
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.TemporaryAccommodationUser
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.TemporaryAccommodationUserRole
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.UserSummary
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.UserWithWorkload
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.Cas1CruManagementAreaEntity
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.UserEntity
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.UserPermission
import uk.gov.justice.digital.hmpps.approvedpremisesapi.jpa.entity.UserQualification
Expand Down Expand Up @@ -54,21 +56,28 @@ class UserTransformer(
)

fun transformJpaToApi(jpa: UserEntity, serviceName: ServiceName) = when (serviceName) {
ServiceName.approvedPremises -> ApprovedPremisesUser(
id = jpa.id,
deliusUsername = jpa.deliusUsername,
roles = jpa.roles.distinctBy { it.role }.mapNotNull(::transformApprovedPremisesRoleToApi),
email = jpa.email,
name = jpa.name,
telephoneNumber = jpa.telephoneNumber,
isActive = jpa.isActive,
qualifications = jpa.qualifications.map(::transformQualificationToApi),
permissions = jpa.roles.distinctBy { it.role }.mapNotNull(::transformApprovedPremisesRoleToPermissionApi).flatten().distinct(),
region = probationRegionTransformer.transformJpaToApi(jpa.probationRegion),
service = "CAS1",
apArea = jpa.apArea?.let { apAreaTransformer.transformJpaToApi(it) } ?: throw InternalServerErrorProblem("CAS1 user ${jpa.id} should have AP Area Set"),
version = UserEntity.getVersionHashCode((jpa.roles.map { it.role })),
)
ServiceName.approvedPremises -> {
val apArea = jpa.apArea ?: throw InternalServerErrorProblem("CAS1 user ${jpa.id} should have AP Area Set")
val cruManagementArea = jpa.cruManagementArea ?: throw InternalServerErrorProblem("CAS1 user ${jpa.id} should have CRU Management Area Set")
ApprovedPremisesUser(
id = jpa.id,
deliusUsername = jpa.deliusUsername,
roles = jpa.roles.distinctBy { it.role }.mapNotNull(::transformApprovedPremisesRoleToApi),
email = jpa.email,
name = jpa.name,
telephoneNumber = jpa.telephoneNumber,
isActive = jpa.isActive,
qualifications = jpa.qualifications.map(::transformQualificationToApi),
permissions = jpa.roles.distinctBy { it.role }.map(::transformApprovedPremisesRoleToPermissionApi).flatten().distinct(),
region = probationRegionTransformer.transformJpaToApi(jpa.probationRegion),
service = "CAS1",
apArea = apArea.let { apAreaTransformer.transformJpaToApi(it) },
cruManagementArea = cruManagementArea.toNamedId(),
cruManagementAreaDefault = apArea.defaultCruManagementArea.toNamedId(),
cruManagementAreaOverride = jpa.cruManagementAreaOverride?.toNamedId(),
version = UserEntity.getVersionHashCode((jpa.roles.map { it.role })),
)
}
ServiceName.temporaryAccommodation -> TemporaryAccommodationUser(
id = jpa.id,
deliusUsername = jpa.deliusUsername,
Expand All @@ -84,6 +93,8 @@ class UserTransformer(
ServiceName.cas2 -> throw RuntimeException("CAS2 not supported")
}

fun Cas1CruManagementAreaEntity.toNamedId() = NamedId(id, name)

fun transformProfileResponseToApi(userName: String, userResponse: UserService.GetUserResponse, xServiceName: ServiceName): ProfileResponse {
return when (userResponse) {
UserService.GetUserResponse.StaffRecordNotFound -> ProfileResponse(userName, ProfileResponse.LoadError.staffRecordNotFound)
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/static/_shared.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3062,12 +3062,26 @@ components:
$ref: '#/components/schemas/ApprovedPremisesUserPermission'
apArea:
$ref: '#/components/schemas/ApArea'
cruManagementArea:
description: CRU Management Area to use. This will be the same as cruManagementAreaDefault unless cruManagementAreaOverride is defined
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaDefault:
description: The CRU Management Area used if no override is defined. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaOverride:
description: The CRU Management Area manually set on this user. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
version:
type: integer
required:
- qualifications
- roles
- apArea
- cruManagementArea
- cruManagementAreaDefault
UserRolesAndQualifications:
type: object
properties:
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/static/codegen/built-api-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7528,12 +7528,26 @@ components:
$ref: '#/components/schemas/ApprovedPremisesUserPermission'
apArea:
$ref: '#/components/schemas/ApArea'
cruManagementArea:
description: CRU Management Area to use. This will be the same as cruManagementAreaDefault unless cruManagementAreaOverride is defined
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaDefault:
description: The CRU Management Area used if no override is defined. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaOverride:
description: The CRU Management Area manually set on this user. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
version:
type: integer
required:
- qualifications
- roles
- apArea
- cruManagementArea
- cruManagementAreaDefault
UserRolesAndQualifications:
type: object
properties:
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/static/codegen/built-cas1-api-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4073,12 +4073,26 @@ components:
$ref: '#/components/schemas/ApprovedPremisesUserPermission'
apArea:
$ref: '#/components/schemas/ApArea'
cruManagementArea:
description: CRU Management Area to use. This will be the same as cruManagementAreaDefault unless cruManagementAreaOverride is defined
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaDefault:
description: The CRU Management Area used if no override is defined. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaOverride:
description: The CRU Management Area manually set on this user. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
version:
type: integer
required:
- qualifications
- roles
- apArea
- cruManagementArea
- cruManagementAreaDefault
UserRolesAndQualifications:
type: object
properties:
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/static/codegen/built-cas2-api-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3653,12 +3653,26 @@ components:
$ref: '#/components/schemas/ApprovedPremisesUserPermission'
apArea:
$ref: '#/components/schemas/ApArea'
cruManagementArea:
description: CRU Management Area to use. This will be the same as cruManagementAreaDefault unless cruManagementAreaOverride is defined
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaDefault:
description: The CRU Management Area used if no override is defined. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaOverride:
description: The CRU Management Area manually set on this user. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
version:
type: integer
required:
- qualifications
- roles
- apArea
- cruManagementArea
- cruManagementAreaDefault
UserRolesAndQualifications:
type: object
properties:
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/static/codegen/built-cas3-api-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3153,12 +3153,26 @@ components:
$ref: '#/components/schemas/ApprovedPremisesUserPermission'
apArea:
$ref: '#/components/schemas/ApArea'
cruManagementArea:
description: CRU Management Area to use. This will be the same as cruManagementAreaDefault unless cruManagementAreaOverride is defined
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaDefault:
description: The CRU Management Area used if no override is defined. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
cruManagementAreaOverride:
description: The CRU Management Area manually set on this user. This is provided to support the user configuration page.
allOf:
- $ref: "#/components/schemas/NamedId"
version:
type: integer
required:
- qualifications
- roles
- apArea
- cruManagementArea
- cruManagementAreaDefault
UserRolesAndQualifications:
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ class UserEntityFactory : Factory<UserEntity> {
this.apArea = { apArea }
}

fun withCruManagementArea(cruManagementArea: Cas1CruManagementAreaEntity?) = apply {
this.cruManagementArea = { cruManagementArea }
}

fun withCruManagementAreaOverride(cruManagementAreaOverride: Cas1CruManagementAreaEntity?) = apply {
this.cruManagementAreaOverride = { cruManagementAreaOverride }
}

fun withTeamCodes(teamCodes: List<String>) = apply {
this.teamCodes = { teamCodes }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.github.bluegroundltd.kfactory.Yielded
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApArea
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUser
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUserRole
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NamedId
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ProbationRegion
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.UserQualification
import uk.gov.justice.digital.hmpps.approvedpremisesapi.util.randomStringMultiCaseWithNumbers
Expand All @@ -21,6 +22,13 @@ class ApprovedPremisesUserFactory : Factory<ApprovedPremisesUser> {
randomStringMultiCaseWithNumbers(20),
)
}
private var cruManagementArea: Yielded<NamedId> = {
NamedId(UUID.randomUUID(), randomStringUpperCase(6))
}
private var cruManagementAreaDefault: Yielded<NamedId> = {
NamedId(UUID.randomUUID(), randomStringUpperCase(6))
}
private var cruManagementAreaOverride: Yielded<NamedId?> = { null }
private var service: Yielded<String> = { randomStringMultiCaseWithNumbers(10) }
private var id: Yielded<UUID> = { UUID.randomUUID() }
private var name: Yielded<String> = { randomStringMultiCaseWithNumbers(20) }
Expand Down Expand Up @@ -83,6 +91,9 @@ class ApprovedPremisesUserFactory : Factory<ApprovedPremisesUser> {
qualifications = this.qualifications(),
roles = this.roles(),
apArea = this.apArea(),
cruManagementArea = this.cruManagementArea(),
cruManagementAreaDefault = this.cruManagementAreaDefault(),
cruManagementAreaOverride = this.cruManagementAreaOverride(),
service = this.service(),
id = this.id(),
name = this.name(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApArea
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApplicationTimeline
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesApplicationStatus
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUser
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NamedId
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.PersonalTimeline
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ProbationRegion
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.TimelineEvent
Expand Down Expand Up @@ -133,6 +134,8 @@ class PersonalTimelineTest : IntegrationTestBase() {
inmateDetail = inmateDetails,
)

val apArea = userEntity.apArea!!

webTestClient.get()
.uri("/people/${offenderDetails.otherIds.crn}/timeline")
.header("Authorization", "Bearer $jwt")
Expand All @@ -155,9 +158,9 @@ class PersonalTimelineTest : IntegrationTestBase() {
roles = emptyList(),
permissions = emptyList(),
apArea = ApArea(
id = userEntity.apArea!!.id,
identifier = userEntity.apArea!!.identifier,
name = userEntity.apArea!!.name,
id = apArea.id,
identifier = apArea.identifier,
name = apArea.name,
),
service = "CAS1",
id = userEntity.id,
Expand All @@ -171,6 +174,15 @@ class PersonalTimelineTest : IntegrationTestBase() {
telephoneNumber = userEntity.telephoneNumber,
isActive = userEntity.isActive,
version = 993,
cruManagementArea = NamedId(
id = userEntity.cruManagementArea!!.id,
name = userEntity.cruManagementArea!!.name,
),
cruManagementAreaDefault = NamedId(
id = apArea.defaultCruManagementArea.id,
name = apArea.defaultCruManagementArea.name,
),
cruManagementAreaOverride = null,
),
timelineEvents = listOf(
TimelineEvent(
Expand Down Expand Up @@ -259,6 +271,8 @@ class PersonalTimelineTest : IntegrationTestBase() {
inmateDetail = null,
)

val apArea = userEntity.apArea!!

webTestClient.get()
.uri("/people/${offenderDetails.otherIds.crn}/timeline")
.header("Authorization", "Bearer $jwt")
Expand All @@ -281,9 +295,9 @@ class PersonalTimelineTest : IntegrationTestBase() {
roles = emptyList(),
permissions = emptyList(),
apArea = ApArea(
id = userEntity.apArea!!.id,
identifier = userEntity.apArea!!.identifier,
name = userEntity.apArea!!.name,
id = apArea.id,
identifier = apArea.identifier,
name = apArea.name,
),
service = "CAS1",
id = userEntity.id,
Expand All @@ -297,6 +311,15 @@ class PersonalTimelineTest : IntegrationTestBase() {
telephoneNumber = userEntity.telephoneNumber,
isActive = userEntity.isActive,
version = 993,
cruManagementArea = NamedId(
id = userEntity.cruManagementArea!!.id,
name = userEntity.cruManagementArea!!.name,
),
cruManagementAreaDefault = NamedId(
id = apArea.defaultCruManagementArea.id,
name = apArea.defaultCruManagementArea.name,
),
cruManagementAreaOverride = null,
),
timelineEvents = listOf(
TimelineEvent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApArea
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUser
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUserPermission
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApprovedPremisesUserRole
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NamedId
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ProbationRegion
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ProfileResponse
import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ServiceName
Expand Down Expand Up @@ -78,6 +79,15 @@ class ProfileTest : IntegrationTestBase() {
service = "CAS1",
isActive = true,
apArea = ApArea(userApArea.id, userApArea.identifier, userApArea.name),
cruManagementArea = NamedId(
id = userEntity.cruManagementArea!!.id,
name = userEntity.cruManagementArea!!.name,
),
cruManagementAreaDefault = NamedId(
id = userApArea.defaultCruManagementArea.id,
name = userApArea.defaultCruManagementArea.name,
),
cruManagementAreaOverride = null,
permissions = listOf(
ApprovedPremisesUserPermission.assessApplication,
ApprovedPremisesUserPermission.assessAppealedApplication,
Expand Down Expand Up @@ -290,6 +300,15 @@ class ProfileTest : IntegrationTestBase() {
service = "CAS1",
isActive = true,
apArea = ApArea(userApArea.id, userApArea.identifier, userApArea.name),
cruManagementArea = NamedId(
id = userEntity.cruManagementArea!!.id,
name = userEntity.cruManagementArea!!.name,
),
cruManagementAreaDefault = NamedId(
id = userApArea.defaultCruManagementArea.id,
name = userApArea.defaultCruManagementArea.name,
),
cruManagementAreaOverride = null,
permissions = listOf(
ApprovedPremisesUserPermission.assessApplication,
ApprovedPremisesUserPermission.assessAppealedApplication,
Expand Down
Loading

0 comments on commit a93b17c

Please sign in to comment.