diff --git a/projects/workforce-allocations-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/LimitedAccessGenerator.kt b/projects/workforce-allocations-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/LimitedAccessGenerator.kt index ed8fa13df4..a7b0db2b5f 100644 --- a/projects/workforce-allocations-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/LimitedAccessGenerator.kt +++ b/projects/workforce-allocations-to-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/LimitedAccessGenerator.kt @@ -5,6 +5,7 @@ import uk.gov.justice.digital.hmpps.entity.LimitedAccessPerson import uk.gov.justice.digital.hmpps.entity.LimitedAccessUser import uk.gov.justice.digital.hmpps.entity.Restriction import uk.gov.justice.digital.hmpps.integrations.delius.person.Person +import uk.gov.justice.digital.hmpps.integrations.delius.provider.StaffWithUser import uk.gov.justice.digital.hmpps.user.AuditUser import java.time.LocalDateTime @@ -13,19 +14,20 @@ object LimitedAccessGenerator { val RESTRICTION = generateRestriction(endDateTime = LocalDateTime.now().plusHours(1)) fun generateExclusion( - user: AuditUser = UserGenerator.LIMITED_ACCESS_USER, + user: LimitedAccessUser = UserGenerator.LIMITED_ACCESS_USER.limitedAccess(), person: Person = PersonGenerator.EXCLUSION, endDateTime: LocalDateTime? = null, id: Long = IdGenerator.getAndIncrement() - ) = Exclusion(person.limitedAccess(), user.limitedAccess(), endDateTime, id) + ) = Exclusion(person.limitedAccess(), user, endDateTime, id) fun generateRestriction( - user: AuditUser = UserGenerator.AUDIT_USER, + user: LimitedAccessUser = StaffGenerator.STAFF_WITH_USER.limitedAccess(), person: Person = PersonGenerator.RESTRICTION, endDateTime: LocalDateTime? = null, id: Long = IdGenerator.getAndIncrement() - ) = Restriction(person.limitedAccess(), user.limitedAccess(), endDateTime, id) + ) = Restriction(person.limitedAccess(), user, endDateTime, id) private fun Person.limitedAccess() = LimitedAccessPerson(crn, exclusionMessage, restrictionMessage, id) private fun AuditUser.limitedAccess() = LimitedAccessUser(username, id) + private fun StaffWithUser.limitedAccess() = LimitedAccessUser(user!!.username, user!!.id) } diff --git a/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt b/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt index 92d8e45c29..3b4d148388 100644 --- a/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt +++ b/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserIntegrationTest.kt @@ -16,7 +16,9 @@ import uk.gov.justice.digital.hmpps.api.model.CaseAccess import uk.gov.justice.digital.hmpps.api.model.CaseAccessList import uk.gov.justice.digital.hmpps.api.model.User import uk.gov.justice.digital.hmpps.api.model.UserAccess +import uk.gov.justice.digital.hmpps.data.generator.LimitedAccessGenerator import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator +import uk.gov.justice.digital.hmpps.data.generator.StaffGenerator import uk.gov.justice.digital.hmpps.data.generator.UserGenerator import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.andExpectJson import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson @@ -39,7 +41,7 @@ class UserIntegrationTest { @Test fun `limited access controls are correctly returned`() { val result = mockMvc.perform( - post("/users/limited-access?username=${UserGenerator.LIMITED_ACCESS_USER.username}") + post("/users/limited-access?username=${LimitedAccessGenerator.EXCLUSION.user.username}") .withToken() .withJson( listOf( @@ -100,7 +102,7 @@ class UserIntegrationTest { @Test fun `limited access controls do not prevent legitimate access`() { val result = mockMvc.perform( - post("/users/limited-access?username=${UserGenerator.AUDIT_USER.username}") + post("/users/limited-access?username=${LimitedAccessGenerator.RESTRICTION.user.username}") .withToken() .withJson( listOf( @@ -131,8 +133,13 @@ class UserIntegrationTest { .andExpectJson( CaseAccessList( crn = PersonGenerator.RESTRICTION_EXCLUSION.crn, - excludedFrom = listOf(User(UserGenerator.LIMITED_ACCESS_USER.username)), - restrictedTo = listOf(User(UserGenerator.AUDIT_USER.username)), + excludedFrom = listOf(User(UserGenerator.LIMITED_ACCESS_USER.username, null)), + restrictedTo = listOf( + User( + StaffGenerator.STAFF_WITH_USER.user!!.username, + StaffGenerator.STAFF_WITH_USER.code + ) + ), exclusionMessage = PersonGenerator.RESTRICTION_EXCLUSION.exclusionMessage, restrictionMessage = PersonGenerator.RESTRICTION_EXCLUSION.restrictionMessage, ) @@ -140,16 +147,17 @@ class UserIntegrationTest { } @Test - fun `get all access limitations filtered by username`() { + fun `get all access limitations filtered by staff code`() { + val staff = StaffGenerator.STAFF_WITH_USER mockMvc.perform( post("/person/${PersonGenerator.RESTRICTION_EXCLUSION.crn}/limited-access") .withToken() - .withJson(listOf(UserGenerator.AUDIT_USER.username)) + .withJson(listOf(staff.code)) ).andExpectJson( CaseAccessList( crn = PersonGenerator.RESTRICTION_EXCLUSION.crn, excludedFrom = emptyList(), - restrictedTo = listOf(User(UserGenerator.AUDIT_USER.username)), + restrictedTo = listOf(User(staff.user!!.username, staff.code)), exclusionMessage = PersonGenerator.RESTRICTION_EXCLUSION.exclusionMessage, restrictionMessage = PersonGenerator.RESTRICTION_EXCLUSION.restrictionMessage, ) @@ -158,7 +166,7 @@ class UserIntegrationTest { mockMvc.perform( post("/person/${PersonGenerator.RESTRICTION_EXCLUSION.crn}/limited-access") .withToken() - .withJson(listOf("SomeOtherUsername")) + .withJson(listOf("OTHER")) ).andExpectJson( CaseAccessList( crn = PersonGenerator.RESTRICTION_EXCLUSION.crn, diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/SharedModels.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/SharedModels.kt index 6ff77bbefe..659194cc81 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/SharedModels.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/SharedModels.kt @@ -14,7 +14,7 @@ data class Name( data class Event(val number: String, val manager: Manager? = null) data class Sentence(val type: String, val date: LocalDate, val length: String) -data class User(val username: String) +data class User(val username: String, val staffCode: String?) data class StaffMember( val code: String, diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/UserResource.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/UserResource.kt index 09f7da79dc..aae214f6b2 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/UserResource.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/UserResource.kt @@ -4,8 +4,6 @@ import io.swagger.v3.oas.annotations.Operation import jakarta.validation.constraints.Size import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.* -import uk.gov.justice.digital.hmpps.api.model.User -import uk.gov.justice.digital.hmpps.service.LdapService import uk.gov.justice.digital.hmpps.service.UserAccessService import uk.gov.justice.digital.hmpps.service.UserService @@ -13,7 +11,6 @@ import uk.gov.justice.digital.hmpps.service.UserService class UserResource( private val userAccessService: UserAccessService, private val userService: UserService, - private val ldapService: LdapService, ) { @PreAuthorize("hasRole('PROBATION_API__WORKFORCE_ALLOCATIONS__CASE_DETAIL')") @@ -37,7 +34,7 @@ class UserResource( @GetMapping("/users") @Operation(summary = "Returns all users with the Delius `MAABT001` role") - fun allUsers() = ldapService.findAllUsersWithRole().map { User(it) } + fun allUsers() = userService.findAllUsersWithRole() @GetMapping("/person/{crn}/limited-access/all") @Operation(summary = "Returns all limited access information (restrictions and exclusions) for a Delius CRN") @@ -47,7 +44,7 @@ class UserResource( @Operation(summary = "Returns limited access information (restrictions and exclusions) for a Delius CRN, given a list of staff codes") fun allAccessLimitationsForCrnAndUserList( @PathVariable crn: String, - @Size(min = 0, max = 500, message = "Please provide up to 500 usernames to filter by") - @RequestBody(required = false) usernames: List? = null, - ) = userService.getAllAccessLimitations(crn, usernames) + @Size(min = 0, max = 500, message = "Please provide up to 500 staff codes to filter by") + @RequestBody(required = false) staffCodes: List? = null, + ) = userService.getAllAccessLimitations(crn, staffCodes) } diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/StaffRepository.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/StaffRepository.kt index 8ba140b312..78c954f6ab 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/StaffRepository.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/StaffRepository.kt @@ -18,6 +18,13 @@ interface StaffRepository : JpaRepository { @Query("select s from StaffWithUser s where upper(s.user.username) = upper(:username)") fun findStaffWithUserByUsername(username: String): StaffWithUser? + @EntityGraph(attributePaths = ["user"]) + @Query("select s from StaffWithUser s where upper(s.user.username) in :usernamesUppercase") + fun findStaffForUsernamesIn( + usernames: List, + usernamesUppercase: List = usernames.map { it.uppercase() } + ): List + @EntityGraph(attributePaths = ["grade.dataset"]) fun findByCode(code: String): Staff? diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/LdapService.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/LdapService.kt index 25b902bb13..6becea583d 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/LdapService.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/LdapService.kt @@ -40,7 +40,8 @@ class LdapService(private val ldapTemplate: LdapTemplate) { .associate { it.username to it.email } @WithSpan - fun findAllUsersWithRole(role: String = "MAABT001"): List = ldapTemplate.search(LdapQueryBuilder.query() + fun findAllUsersWithRole(role: String): List = ldapTemplate.search( + LdapQueryBuilder.query() .attributes("entryDN") .searchScope(SearchScope.SUBTREE) .where("cn").`is`(role) diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt index e95c340fb4..a381e335c8 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt @@ -5,6 +5,7 @@ import uk.gov.justice.digital.hmpps.api.model.CaseAccessList import uk.gov.justice.digital.hmpps.api.model.User import uk.gov.justice.digital.hmpps.exception.NotFoundException import uk.gov.justice.digital.hmpps.integrations.delius.person.PersonRepository +import uk.gov.justice.digital.hmpps.integrations.delius.provider.StaffRepository import uk.gov.justice.digital.hmpps.integrations.delius.user.ExclusionRepository import uk.gov.justice.digital.hmpps.integrations.delius.user.RestrictionRepository @@ -12,21 +13,31 @@ import uk.gov.justice.digital.hmpps.integrations.delius.user.RestrictionReposito class UserService( private val personRepository: PersonRepository, private val exclusionRepository: ExclusionRepository, - private val restrictionRepository: RestrictionRepository + private val restrictionRepository: RestrictionRepository, + private val staffRepository: StaffRepository, + private val ldapService: LdapService, ) { - fun getAllAccessLimitations(crn: String, usernamesFilter: List? = null): CaseAccessList { + fun getAllAccessLimitations(crn: String, staffCodesFilter: List? = null): CaseAccessList { val person = personRepository.findByCrnAndSoftDeletedFalse(crn) ?: throw NotFoundException("Person", "crn", crn) + val exclusions = exclusionRepository.findByPersonId(person.id).map { it.user.username } + val restrictions = restrictionRepository.findByPersonId(person.id).map { it.user.username } + val staffCodes = staffRepository.findStaffForUsernamesIn(exclusions + restrictions) + .associate { it.user?.username to it.code } return CaseAccessList( crn = crn, exclusionMessage = person.exclusionMessage, restrictionMessage = person.restrictionMessage, - excludedFrom = exclusionRepository.findByPersonId(person.id).map { it.user.username } - .filter { usernamesFilter == null || it in usernamesFilter } - .map { User(it) }, - restrictedTo = restrictionRepository.findByPersonId(person.id).map { it.user.username } - .filter { usernamesFilter == null || it in usernamesFilter } - .map { User(it) }, + excludedFrom = exclusions.map { User(it, staffCodes[it]) } + .filter { staffCodesFilter == null || it.staffCode in staffCodesFilter }, + restrictedTo = restrictions.map { User(it, staffCodes[it]) } + .filter { staffCodesFilter == null || it.staffCode in staffCodesFilter }, ) } + + fun findAllUsersWithRole(role: String = "MAABT001"): List { + val usernames = ldapService.findAllUsersWithRole(role) + val staff = staffRepository.findStaffForUsernamesIn(usernames) + return staff.map { User(it.user!!.username, it.code) } + } }