diff --git a/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserLocationIntegrationTest.kt b/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserLocationIntegrationTest.kt index 7e442745ee..c0e73b6a91 100644 --- a/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserLocationIntegrationTest.kt +++ b/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/UserLocationIntegrationTest.kt @@ -8,7 +8,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print import org.springframework.test.web.servlet.result.MockMvcResultMatchers import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import uk.gov.justice.digital.hmpps.api.model.sentence.Address @@ -36,7 +35,6 @@ class UserLocationIntegrationTest { @Test fun `user not found`() { mockMvc.perform(MockMvcRequestBuilders.get("/user/user/locations").withToken()) - .andDo(print()) .andExpect(MockMvcResultMatchers.status().isNotFound) .andExpect(jsonPath("$.message", equalTo("User with username of user not found"))) } @@ -44,7 +42,6 @@ class UserLocationIntegrationTest { @Test fun `get user locations`() { val response = mockMvc.perform(MockMvcRequestBuilders.get("/user/peter-parker/locations").withToken()) - .andDo(print()) .andExpect(MockMvcResultMatchers.status().isOk) .andReturn().response.contentAsJson() 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 3b4d148388..79e38616bf 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 @@ -2,16 +2,15 @@ package uk.gov.justice.digital.hmpps import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.equalToIgnoringCase import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* 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 @@ -34,8 +33,11 @@ class UserIntegrationTest { @Test fun `get all users`() { mockMvc.perform(get("/users").withToken()) + .andExpect(request().asyncStarted()) + .andDo(MvcResult::getAsyncResult) .andExpect(status().is2xxSuccessful) - .andExpect(jsonPath("$[0].username", equalToIgnoringCase("JoeBloggs"))) + .andExpect(content().contentTypeCompatibleWith("application/json")) + .andExpect(content().json("""[{"username":"JoeBloggs","staffCode":"N02ABS1"}]""")) } @Test 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 aae214f6b2..4b2fe29ae5 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 @@ -2,8 +2,11 @@ package uk.gov.justice.digital.hmpps.api.resource import io.swagger.v3.oas.annotations.Operation import jakarta.validation.constraints.Size +import org.springframework.http.MediaType.APPLICATION_JSON +import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.* +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody import uk.gov.justice.digital.hmpps.service.UserAccessService import uk.gov.justice.digital.hmpps.service.UserService @@ -34,7 +37,9 @@ class UserResource( @GetMapping("/users") @Operation(summary = "Returns all users with the Delius `MAABT001` role") - fun allUsers() = userService.findAllUsersWithRole() + fun allUsers() = ResponseEntity.ok() + .contentType(APPLICATION_JSON) + .body(StreamingResponseBody { userService.writeAllUsersWithRole(it) }) @GetMapping("/person/{crn}/limited-access/all") @Operation(summary = "Returns all limited access information (restrictions and exclusions) for a Delius CRN") 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 78c954f6ab..cbbc3960dc 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 @@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import uk.gov.justice.digital.hmpps.exception.NotFoundException import java.time.LocalDate +import java.util.stream.Stream interface StaffRepository : JpaRepository { @EntityGraph(attributePaths = ["grade.dataset", "user"]) @@ -23,7 +24,7 @@ interface StaffRepository : JpaRepository { fun findStaffForUsernamesIn( usernames: List, usernamesUppercase: List = usernames.map { it.uppercase() } - ): List + ): Stream @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/UserService.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/UserService.kt index a381e335c8..1d0f716b81 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 @@ -1,5 +1,7 @@ package uk.gov.justice.digital.hmpps.service +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.transaction.Transactional import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.api.model.CaseAccessList import uk.gov.justice.digital.hmpps.api.model.User @@ -8,20 +10,25 @@ 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 +import java.io.OutputStream +import java.util.stream.Stream +import kotlin.streams.asSequence @Service +@Transactional class UserService( private val personRepository: PersonRepository, private val exclusionRepository: ExclusionRepository, private val restrictionRepository: RestrictionRepository, private val staffRepository: StaffRepository, private val ldapService: LdapService, + private val objectMapper: ObjectMapper, ) { 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) + val staffCodes = staffRepository.findStaffForUsernamesIn(exclusions + restrictions).asSequence() .associate { it.user?.username to it.code } return CaseAccessList( crn = crn, @@ -34,10 +41,20 @@ class UserService( ) } - fun findAllUsersWithRole(role: String = "MAABT001"): List { + fun findAllUsersWithRole(role: String = "MAABT001"): Stream { val usernames = ldapService.findAllUsersWithRole(role) val staff = staffRepository.findStaffForUsernamesIn(usernames) return staff.map { User(it.user!!.username, it.code) } } + + fun writeAllUsersWithRole(outputStream: OutputStream) { + objectMapper.factory.createGenerator(outputStream).use { json -> + json.writeStartArray() + findAllUsersWithRole().use { users -> + users.forEach { user -> json.writeObject(user) } + } + json.writeEndArray() + } + } }