Skip to content

Commit

Permalink
PI-1555 added document endpoints (#2383)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevomcallister authored Oct 13, 2023
1 parent 2e45f06 commit 5a11c83
Show file tree
Hide file tree
Showing 38 changed files with 1,358 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ generic-service:
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/issuer
INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api-dev.hmpps.service.justice.gov.uk

INTEGRATIONS_ALFRESCO_URL: https://alfresco.test.delius.probation.hmpps.dsd.io/alfresco/service/noms-spg/
LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG

generic-prometheus-alerts:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ generic-service:
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth/issuer
INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api-preprod.hmpps.service.justice.gov.uk
INTEGRATIONS_ALFRESCO_URL: https://alfresco.pre-prod.delius.probation.hmpps.dsd.io/alfresco/service/noms-spg/

generic-prometheus-alerts:
businessHoursOnly: true
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ generic-service:
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: https://sign-in.hmpps.service.justice.gov.uk/auth/issuer
INTEGRATIONS_APPROVED-PREMISES-API_URL: https://approved-premises-api.hmpps.service.justice.gov.uk
INTEGRATIONS_ALFRESCO_URL: https://alfresco.probation.service.justice.gov.uk/alfresco/service/noms-spg/
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import uk.gov.justice.digital.hmpps.data.generator.CaseloadGenerator
import uk.gov.justice.digital.hmpps.data.generator.ContactOutcomeGenerator
import uk.gov.justice.digital.hmpps.data.generator.ContactTypeGenerator
import uk.gov.justice.digital.hmpps.data.generator.DatasetGenerator
import uk.gov.justice.digital.hmpps.data.generator.DocumentGenerator
import uk.gov.justice.digital.hmpps.data.generator.NsiStatusGenerator
import uk.gov.justice.digital.hmpps.data.generator.NsiTypeGenerator
import uk.gov.justice.digital.hmpps.data.generator.OfficeLocationGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.ANOTHER_EVENT
import uk.gov.justice.digital.hmpps.data.generator.PersonManagerGenerator
import uk.gov.justice.digital.hmpps.data.generator.ProbationAreaGenerator
import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator
Expand All @@ -34,6 +36,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.caseload.CaseloadReposit
import uk.gov.justice.digital.hmpps.integrations.delius.contact.outcome.ContactOutcomeRepository
import uk.gov.justice.digital.hmpps.integrations.delius.contact.type.ContactTypeCode
import uk.gov.justice.digital.hmpps.integrations.delius.contact.type.ContactTypeRepository
import uk.gov.justice.digital.hmpps.integrations.delius.document.DocumentRepository
import uk.gov.justice.digital.hmpps.integrations.delius.location.OfficeLocationRepository
import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.NsiStatusCode
import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.NsiStatusRepository
Expand Down Expand Up @@ -83,7 +86,8 @@ class DataLoader(
private val referralRepository: ReferralRepository,
private val probationCaseDataLoader: ProbationCaseDataLoader,
private val lduRepository: LduRepository,
private val staffUserRepository: StaffUserRepository
private val staffUserRepository: StaffUserRepository,
private val documentRepository: DocumentRepository
) : ApplicationListener<ApplicationReadyEvent> {

@PostConstruct
Expand Down Expand Up @@ -188,8 +192,12 @@ class DataLoader(
caseloadRepository.save(CaseloadGenerator.generate(person, TeamGenerator.APPROVED_PREMISES_TEAM))
caseloadRepository.save(CaseloadGenerator.generate(person, TeamGenerator.UNALLOCATED))

eventRepository.save(ANOTHER_EVENT)
referralRepository.save(ReferralGenerator.EXISTING_REFERRAL)

documentRepository.save(DocumentGenerator.EVENT_DOC)
documentRepository.save(DocumentGenerator.PERSON_DOC)

probationCaseDataLoader.loadData()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package uk.gov.justice.digital.hmpps.data.generator

import uk.gov.justice.digital.hmpps.integrations.delius.approvedpremises.referral.entity.Event
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.DocEvent
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.DocumentType
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.EventDocument
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.OffenderDocument
import uk.gov.justice.digital.hmpps.integrations.delius.person.Person
import java.time.ZonedDateTime

object DocumentGenerator {
val EVENT_DOC = generateEventDoc()
val PERSON_DOC = generatePersonDoc()

fun generateEventDoc(
event: Event = PersonGenerator.ANOTHER_EVENT,
id: Long = IdGenerator.getAndIncrement()
): EventDocument {
val doc = EventDocument(event.toDocEvent())
doc.id = id
doc.person = PersonGenerator.DEFAULT
doc.name = "test.doc"
doc.primaryKeyId = doc.event?.id!!
doc.alfrescoId = "uuid1"
doc.lastSaved = ZonedDateTime.now().minusDays(7)
doc.dateProduced = null
doc.type = DocumentType.DOCUMENT
return doc
}

fun generatePersonDoc(
id: Long = IdGenerator.getAndIncrement()
): OffenderDocument {
val doc = OffenderDocument()
doc.id = id
doc.person = PersonGenerator.DEFAULT
doc.name = "offender.doc"
doc.primaryKeyId = PersonGenerator.DEFAULT.id
doc.alfrescoId = "uuid2"
doc.lastSaved = ZonedDateTime.now().minusDays(7)
doc.dateProduced = null
doc.type = DocumentType.DOCUMENT

return doc
}

private fun Event.toDocEvent() =
DocEvent(id, Person(personId, "", false), true, number, null, null)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention
import uk.gov.justice.digital.hmpps.integrations.delius.nonstatutoryintervention.entity.NsiType

object NsiTypeGenerator {
fun generate(code: String, id: Long = IdGenerator.getAndIncrement()) = NsiType(id, code)
fun generate(code: String, id: Long = IdGenerator.getAndIncrement()) = NsiType(id, code, "description of $code")
}

object NsiStatusGenerator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import java.time.ZonedDateTime
object PersonGenerator {
val DEFAULT = generate(crn = "A000001")
val EVENT = generateEvent("7", DEFAULT.id)
val ANOTHER_EVENT = generateEvent("8", DEFAULT.id)
fun generate(
crn: String,
id: Long = IdGenerator.getAndIncrement()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object ReferralGenerator {

fun generateReferral(
person: Person = PersonGenerator.DEFAULT,
eventId: Long = IdGenerator.getAndIncrement(),
eventId: Long = PersonGenerator.ANOTHER_EVENT.id,
approvedPremises: ApprovedPremises = ApprovedPremisesGenerator.DEFAULT,
referralDate: LocalDate = LocalDate.now(),
expectedArrivalDate: LocalDate? = LocalDate.now().plusDays(1),
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"request": {
"method": "GET",
"urlPath": "/alfresco/fetch/uuid1"
},
"response": {
"headers": {
"Content-Type": "application/octet-stream",
"Content-Disposition": "attachment; filename=\"doc1\"; filename*=UTF-8''doc1",
"Custom-Alfresco-Header": "should be ignored"
},
"status": 200,
"bodyFileName": "document.pdf"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package uk.gov.justice.digital.hmpps

import com.github.tomakehurst.wiremock.WireMockServer
import org.hamcrest.Matchers
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.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.header
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.util.ResourceUtils
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
import uk.gov.justice.digital.hmpps.security.withOAuth2Token

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
internal class DocIntegrationTest {
@Autowired
lateinit var mockMvc: MockMvc

@Autowired
lateinit var wireMockserver: WireMockServer

@Test
fun `document is downloaded`() {
mockMvc.perform(
get("/documents/A000001/uuid1").accept("application/octet-stream").withOAuth2Token(wireMockserver)
)
.andExpect(status().is2xxSuccessful)
.andExpect(header().string("Content-Type", "application/octet-stream"))
.andExpect(
header().string(
"Content-Disposition",
"attachment; filename=\"=?UTF-8?Q?test.doc?=\"; filename*=UTF-8''test.doc"
)
)
.andExpect(header().doesNotExist("Custom-Alfresco-Header"))
.andExpect(content().bytes(ResourceUtils.getFile("classpath:simulations/__files/document.pdf").readBytes()))
}

@Test
fun `list documents`() {
mockMvc.perform(get("/documents/${PersonGenerator.DEFAULT.crn}/all").withOAuth2Token(wireMockserver))
.andExpect(status().isOk)
.andExpect(MockMvcResultMatchers.jsonPath("$[0].id", Matchers.equalTo("uuid1")))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].level", Matchers.equalTo("Conviction")))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].eventNumber", Matchers.equalTo("8")))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].filename", Matchers.equalTo("test.doc")))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].typeCode", Matchers.equalTo("EVENT")))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].typeDescription", Matchers.equalTo("Event")))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].id", Matchers.equalTo("uuid2")))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].level", Matchers.equalTo("Offender")))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].filename", Matchers.equalTo("offender.doc")))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].typeCode", Matchers.equalTo("PERSON")))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].typeDescription", Matchers.equalTo("Person")))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.context.annotation.Configuration
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager
import uk.gov.justice.digital.hmpps.config.feign.FeignConfig
import uk.gov.justice.digital.hmpps.integrations.alfresco.AlfrescoClient
import uk.gov.justice.digital.hmpps.integrations.approvedpremises.ApprovedPremisesApiClient

@Configuration
@EnableFeignClients(clients = [ApprovedPremisesApiClient::class])
@EnableFeignClients(clients = [ApprovedPremisesApiClient::class, AlfrescoClient::class])
class FeignOAuth2Config(
authorizedClientManager: OAuth2AuthorizedClientManager
) : FeignConfig(authorizedClientManager) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package uk.gov.justice.digital.hmpps.controller

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.APDocument
import uk.gov.justice.digital.hmpps.service.DocumentService

@RestController
@Tag(name = "Documents")
@RequestMapping("/documents/{crn}")
@PreAuthorize("hasRole('ROLE_APPROVED_PREMISES_STAFF')")
class DocumentController(private val documentService: DocumentService) {

@GetMapping(value = ["/{id}"])
@Operation(summary = "Download document content")
fun downloadDocument(
@PathVariable crn: String,
@PathVariable id: String
) = documentService.downloadDocument(crn, id)

@PreAuthorize("hasRole('ROLE_APPROVED_PREMISES_STAFF')")
@Operation(
summary = "List of documents held in Delius for the probation case",
description = """List of documents available in Delius for the probation
case identified by the CRN provided in the request. Document list
includes summary information on the type and purpose of document held.
"""
)
@GetMapping(value = ["/all"])
fun findDocuments(@PathVariable crn: String): List<APDocument> =
documentService.getDocumentsByCrn(crn)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package uk.gov.justice.digital.hmpps.integrations.alfresco

import feign.RequestInterceptor
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.context.annotation.Bean
import org.springframework.core.io.Resource
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import uk.gov.justice.digital.hmpps.security.ServiceContext

@FeignClient(name = "alfresco", url = "\${integrations.alfresco.url}", configuration = [AlfrescoFeignConfig::class])
interface AlfrescoClient {
@GetMapping(value = ["/fetch/{id}"])
fun getDocument(@PathVariable id: String): ResponseEntity<Resource>
}

class AlfrescoFeignConfig {
@Bean
fun requestInterceptor() = RequestInterceptor { template ->
template.header("X-DocRepository-Remote-User", "N00")
template.header("X-DocRepository-Real-Remote-User", ServiceContext.servicePrincipal()!!.username)
template.header("Content-Type: multipart/form-data")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Referral(
@Column(name = "offender_id")
val personId: Long,

@Column(name = "event_id")
val eventId: Long,
val approvedPremisesId: Long,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class Contact(
@JoinColumn(name = "offender_id", nullable = false)
val person: Person,

@Column(name = "event_id")
val eventId: Long? = null,

@Lob
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package uk.gov.justice.digital.hmpps.integrations.delius.document

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import uk.gov.justice.digital.hmpps.integrations.delius.document.entity.Document

interface DocumentRepository : JpaRepository<Document, Long> {
@Query("select d.name from Document d where d.person.crn = :crn and d.alfrescoId = :alfrescoId")
fun findNameByPersonCrnAndAlfrescoId(crn: String, alfrescoId: String): String?

fun findAllByPersonIdAndSoftDeletedIsFalse(personId: Long): List<Document>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uk.gov.justice.digital.hmpps.integrations.delius.document.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 uk.gov.justice.digital.hmpps.integrations.delius.referencedata.ReferenceData

@Entity
@Immutable
@Table(name = "approved_premises_referral")
class ApprovedPremisesReferral(
@Id
@Column(name = "approved_premises_referral_id")
val id: Long,

@JoinColumn(name = "event_id", insertable = false, updatable = false)
@ManyToOne
val event: DocEvent,

@JoinColumn(name = "referral_category_id", insertable = false, updatable = false)
@ManyToOne
val category: ReferenceData

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package uk.gov.justice.digital.hmpps.integrations.delius.document.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

@Entity
@Immutable
@Table(name = "case_allocation")
class CaseAllocationDoc(
@Id
@Column(name = "case_allocation_id")
val id: Long,

@JoinColumn(name = "event_id", insertable = false, updatable = false)
@ManyToOne
val event: DocEvent
)
Loading

0 comments on commit 5a11c83

Please sign in to comment.