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

PI-1495 - make Workforce API consistent with R&M #2316

Merged
merged 5 commits into from
Sep 28, 2023
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
20 changes: 20 additions & 0 deletions libs/limited-access/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import uk.gov.justice.digital.hmpps.extensions.ClassPathExtension

dependencies {
compileOnly("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-data-jpa")
testImplementation(libs.bundles.mockito)
}

configure<ClassPathExtension> {
jacocoExclusions = listOf(
"**/exception/**",
"**/config/**",
"**/entity**",
"**/logging/**"
)
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity
package uk.gov.justice.digital.hmpps.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import org.hibernate.annotations.Immutable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Person
import uk.gov.justice.digital.hmpps.user.AuditUser
import java.time.LocalDateTime

@Immutable
@Entity
class Exclusion(

@ManyToOne
@JoinColumn(name = "offender_id")
val person: Person,
val person: LimitedAccessPerson,

@ManyToOne
@JoinColumn(name = "user_id")
val user: AuditUser,
val user: LimitedAccessUser,

@Column(name = "exclusion_end_time")
val end: LocalDateTime?,
Expand All @@ -34,13 +34,14 @@ class Exclusion(
@Immutable
@Entity
class Restriction(

@ManyToOne
@JoinColumn(name = "offender_id")
val person: Person,
val person: LimitedAccessPerson,

@ManyToOne
@JoinColumn(name = "user_id")
val user: AuditUser,
val user: LimitedAccessUser,

@Column(name = "restriction_end_time")
val end: LocalDateTime?,
Expand All @@ -50,16 +51,45 @@ class Restriction(
val id: Long
)

interface UserAccessRepository : JpaRepository<AuditUser, Long> {
@Immutable
@Entity
@Table(name = "offender")
class LimitedAccessPerson(

@Column(columnDefinition = "char(7)")
val crn: String,

val exclusionMessage: String?,
val restrictionMessage: String?,

@Id
@Column(name = "offender_id")
val id: Long
)

@Immutable
@Entity
@Table(name = "user_")
class LimitedAccessUser(

@Column(name = "distinguished_name")
val username: String,

@Id
@Column(name = "user_id")
val id: Long
)

interface UserAccessRepository : JpaRepository<LimitedAccessUser, Long> {
@Query(
"""
select p.crn as crn, '' as exclusionMessage, p.restrictionMessage as restrictionMessage
from Person p where p.crn in :crns
from LimitedAccessPerson p where p.crn in :crns
and exists (select r from Restriction r where r.person.id = p.id and (r.end is null or r.end > current_date ))
and not exists (select r from Restriction r where upper(r.user.username) = upper(:username) and r.person.id = p.id and (r.end is null or r.end > current_date ))
union
select p.crn as crn, p.exclusionMessage as exclusionMessage, '' as restrictionMessage
from Person p where p.crn in :crns
from LimitedAccessPerson p where p.crn in :crns
and exists (select e from Exclusion e where upper(e.user.username) = upper(:username) and e.person.id = p.id and (e.end is null or e.end > current_date ))
"""
)
Expand All @@ -71,3 +101,6 @@ interface PersonAccess {
val exclusionMessage: String?
val restrictionMessage: String?
}

fun PersonAccess.isExcluded() = !exclusionMessage.isNullOrBlank()
fun PersonAccess.isRestricted() = !restrictionMessage.isNullOrBlank()
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package uk.gov.justice.digital.hmpps.service

import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.entity.PersonAccess
import uk.gov.justice.digital.hmpps.entity.UserAccessRepository
import uk.gov.justice.digital.hmpps.entity.isExcluded
import uk.gov.justice.digital.hmpps.entity.isRestricted

@Service
class UserAccessService(private val uar: UserAccessRepository) {
fun userAccessFor(username: String, crns: List<String>): UserAccess {
val limitations: Map<String, List<PersonAccess>> = uar.getAccessFor(username, crns).groupBy { it.crn }
return UserAccess(crns.map { limitations[it].combined(it) })
}

private fun List<PersonAccess>?.combined(crn: String): CaseAccess {
return if (this == null) {
CaseAccess(crn, userExcluded = false, userRestricted = false)
} else {
CaseAccess(
crn,
any { it.isExcluded() },
any { it.isRestricted() },
firstOrNull { it.isExcluded() }?.exclusionMessage,
firstOrNull { it.isRestricted() }?.restrictionMessage
)
}
}
}

data class CaseAccess(
val crn: String,
val userExcluded: Boolean,
val userRestricted: Boolean,
val exclusionMessage: String? = null,
val restrictionMessage: String? = null
)

data class UserAccess(val access: List<CaseAccess>)
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package uk.gov.justice.digital.hmpps.service

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.whenever
import uk.gov.justice.digital.hmpps.entity.PersonAccess
import uk.gov.justice.digital.hmpps.entity.UserAccessRepository

@ExtendWith(MockitoExtension::class)
internal class UserAccessServiceTest {
@Mock
internal lateinit var uar: UserAccessRepository

@InjectMocks
internal lateinit var userAccessService: UserAccessService

@Test
fun `user limited access is correctly returned`() {
givenLimitedAccessResults()
val res = userAccessService.userAccessFor("john-smith", listOf("E123456", "R123456", "B123456", "N123456"))

assertThat(res.access.size, equalTo(4))
assertThat(res, equalTo(userAccess()))
}

private fun givenLimitedAccessResults() {
val personAccesses = listOf(
object : PersonAccess {
override val crn = "E123456"
override val exclusionMessage = "This person has an exclusion"
override val restrictionMessage = null
},
object : PersonAccess {
override val crn = "R123456"
override val exclusionMessage = null
override val restrictionMessage = "This person has a restriction"
},
object : PersonAccess {
override val crn = "B123456"
override val exclusionMessage = "This person has an exclusion"
override val restrictionMessage = "This person has a restriction"
},
object : PersonAccess {
override val crn = "N123456"
override val exclusionMessage = null
override val restrictionMessage = null
}
)

whenever(uar.getAccessFor("john-smith", listOf("E123456", "R123456", "B123456", "N123456")))
.thenReturn(personAccesses)
}

private fun userAccess(): UserAccess =
UserAccess(
listOf(
CaseAccess("E123456", userExcluded = true, userRestricted = false, "This person has an exclusion"),
CaseAccess(
"R123456",
userExcluded = false,
userRestricted = true,
restrictionMessage = "This person has a restriction"
),
CaseAccess(
"B123456",
userExcluded = true,
userRestricted = true,
"This person has an exclusion",
"This person has a restriction"
),
CaseAccess("N123456", userExcluded = false, userRestricted = false)
)
)
}
1 change: 1 addition & 0 deletions projects/refer-and-monitor-and-delius/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ apply(plugin = "com.google.cloud.tools.jib")
dependencies {
implementation(project(":libs:audit"))
implementation(project(":libs:commons"))
implementation(project(":libs:limited-access"))
implementation(project(":libs:messaging"))
implementation(project(":libs:oauth-client"))
implementation(project(":libs:oauth-server"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator
import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator
import uk.gov.justice.digital.hmpps.data.generator.SentenceGenerator
import uk.gov.justice.digital.hmpps.data.generator.UserGenerator
import uk.gov.justice.digital.hmpps.entity.Exclusion
import uk.gov.justice.digital.hmpps.entity.Restriction
import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode
import uk.gov.justice.digital.hmpps.integrations.delius.contact.ContactOutcomeRepository
import uk.gov.justice.digital.hmpps.integrations.delius.contact.ContactRepository
Expand All @@ -30,8 +32,6 @@ import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.DisposalTyp
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.EventRepository
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.MainOffence
import uk.gov.justice.digital.hmpps.integrations.delius.event.entity.Offence
import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.Exclusion
import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.Restriction
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Disability
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository
import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonDetailRepository
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.Exclusion
import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.Restriction
import uk.gov.justice.digital.hmpps.entity.Exclusion
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.entity.Person
import uk.gov.justice.digital.hmpps.user.AuditUser
import java.time.LocalDateTime
Expand All @@ -15,12 +17,15 @@ object LimitedAccessGenerator {
user: AuditUser = UserGenerator.LIMITED_ACCESS_USER,
endDateTime: LocalDateTime? = null,
id: Long = IdGenerator.getAndIncrement()
) = Exclusion(person, user, endDateTime, id)
) = Exclusion(person.limitedAccess(), user.limitedAccess(), endDateTime, id)

fun generateRestriction(
person: Person,
user: AuditUser = UserGenerator.AUDIT_USER,
endDateTime: LocalDateTime? = null,
id: Long = IdGenerator.getAndIncrement()
) = Restriction(person, user, endDateTime, id)
) = Restriction(person.limitedAccess(), user.limitedAccess(), endDateTime, id)

private fun Person.limitedAccess() = LimitedAccessPerson(crn, exclusionMessage, restrictionMessage, id)
private fun AuditUser.limitedAccess() = LimitedAccessUser(username, id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import uk.gov.justice.digital.hmpps.api.model.CaseAccess
import uk.gov.justice.digital.hmpps.api.model.CaseIdentifier
import uk.gov.justice.digital.hmpps.api.model.ManagedCases
import uk.gov.justice.digital.hmpps.api.model.Name
import uk.gov.justice.digital.hmpps.api.model.UserAccess
import uk.gov.justice.digital.hmpps.api.model.UserDetail
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.UserGenerator
import uk.gov.justice.digital.hmpps.security.withOAuth2Token
import uk.gov.justice.digital.hmpps.service.CaseAccess
import uk.gov.justice.digital.hmpps.service.UserAccess

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import uk.gov.justice.digital.hmpps.api.model.ManagedCases
import uk.gov.justice.digital.hmpps.api.model.UserAccess
import uk.gov.justice.digital.hmpps.api.model.UserDetail
import uk.gov.justice.digital.hmpps.service.ManagerService
import uk.gov.justice.digital.hmpps.service.UserAccess
import uk.gov.justice.digital.hmpps.service.UserService

@Validated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,17 @@ package uk.gov.justice.digital.hmpps.service

import org.springframework.ldap.core.LdapTemplate
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.api.model.CaseAccess
import uk.gov.justice.digital.hmpps.api.model.Name
import uk.gov.justice.digital.hmpps.api.model.UserAccess
import uk.gov.justice.digital.hmpps.api.model.UserDetail
import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.PersonAccess
import uk.gov.justice.digital.hmpps.integrations.delius.limitedaccess.entity.UserAccessRepository
import uk.gov.justice.digital.hmpps.integrations.ldap.entity.LdapUserDetails
import uk.gov.justice.digital.hmpps.ldap.findByUsername

@Service
class UserService(private val uar: UserAccessRepository, private val ldapTemplate: LdapTemplate) {
class UserService(private val userAccessService: UserAccessService, private val ldapTemplate: LdapTemplate) {

fun userDetails(username: String): UserDetail? = ldapTemplate.findByUsername<LdapUserDetails>(username)?.let {
UserDetail(it.username, Name(it.forename, it.surname), it.email)
}

fun userAccessFor(username: String, crns: List<String>): UserAccess {
val limitations: Map<String, List<PersonAccess>> = uar.getAccessFor(username, crns).groupBy { it.crn }
return UserAccess(crns.map { limitations[it].combined(it) })
}

private fun List<PersonAccess>?.combined(crn: String): CaseAccess {
return if (this == null) {
CaseAccess(crn, userExcluded = false, userRestricted = false)
} else {
CaseAccess(
crn,
any { !it.exclusionMessage.isNullOrBlank() },
any { !it.restrictionMessage.isNullOrBlank() },
firstOrNull { !it.exclusionMessage.isNullOrBlank() }?.exclusionMessage,
firstOrNull { !it.restrictionMessage.isNullOrBlank() }?.restrictionMessage
)
}
}
fun userAccessFor(username: String, crns: List<String>) = userAccessService.userAccessFor(username, crns)
}
1 change: 1 addition & 0 deletions projects/workforce-allocations-to-delius/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ apply(plugin = "com.google.cloud.tools.jib")
dependencies {
implementation(project(":libs:audit"))
implementation(project(":libs:commons"))
implementation(project(":libs:limited-access"))
implementation(project(":libs:messaging"))
implementation(project(":libs:oauth-client"))
implementation(project(":libs:oauth-server"))
Expand Down
Loading