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

DST-18168 initial pdf generation #4

Closed
wants to merge 29 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6dae659
initial setup and endpoints
Jan 15, 2025
70b57e6
initial setup and endpoints
Jan 20, 2025
57c5590
formatting changes
Jan 21, 2025
b09daf9
initial save functionality
Jan 24, 2025
73df1b1
Added tests, dockerised database for testing. Tidy of initial flyway …
Jan 27, 2025
e0a62d5
Updated to address
Jan 28, 2025
8a3be62
added page save variables to details object
Jan 28, 2025
02c9392
new fields to maintain state of selections on the basic details page
Jan 29, 2025
72a60c7
schema update, created/updated fixed for breachnotice
Jan 31, 2025
6c24734
mapped titleandfullname
Jan 31, 2025
0fd3fc9
Updated Tests
Feb 3, 2025
8e422f8
Updated Tests
Feb 3, 2025
da4150d
Add postgres container to CircleCI
marcus-bcl Feb 3, 2025
35bcc14
Added Type Description
Feb 3, 2025
d4244fc
Merge remote-tracking branch 'origin/initial' into initial
Feb 3, 2025
b01beb4
added 2 descriptions to schema, code clearup, removed unused code
Feb 5, 2025
c3da878
mappings for new values
Feb 5, 2025
378c017
DST-18168 initial pdf generation
karlfosterBCL Feb 7, 2025
a108f15
DST-18140 - Crud Operations for the Breach Notice Service (#3)
peter-bcl Feb 10, 2025
0838e5d
initial setup and endpoints
Jan 15, 2025
3e5ac80
formatting changes
Jan 21, 2025
e6648a5
initial save functionality
Jan 24, 2025
01d8781
Added tests, dockerised database for testing. Tidy of initial flyway …
Jan 27, 2025
b435b8c
Updated to address
Jan 28, 2025
72f2264
Updated Tests
Feb 3, 2025
efbe12f
Updated Tests
Feb 3, 2025
95ff491
added 2 descriptions to schema, code clearup, removed unused code
Feb 5, 2025
4c73b87
DST-18168 initial pdf generation
karlfosterBCL Feb 7, 2025
6d1692f
draft function proof of concept
karlfosterBCL Feb 11, 2025
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
Prev Previous commit
Next Next commit
Added tests, dockerised database for testing. Tidy of initial flyway …
…schema
peter committed Jan 27, 2025
commit 73df1b1dcf5805ccbd1f57243d441151cfe77cde
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ dependencies {

testImplementation("uk.gov.justice.service.hmpps:hmpps-kotlin-spring-boot-starter-test:1.0.5")
testImplementation("org.wiremock:wiremock-standalone:3.9.1")
testImplementation("org.testcontainers:postgresql")
testImplementation("io.swagger.parser.v3:swagger-parser:2.1.22") {
exclude(group = "io.swagger.core.v3")
}
Original file line number Diff line number Diff line change
@@ -6,7 +6,9 @@ import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.security.SecurityRequirement
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.validation.Valid
import org.springframework.http.HttpStatus
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.PostMapping
@@ -23,7 +25,7 @@ import java.util.*

@RestController
// Role here is specific to the UI.
// @PreAuthorize("hasRole('ROLE_TEMPLATE_KOTLIN__UI')")
@PreAuthorize("hasRole('ROLE_TEMPLATE_KOTLIN__UI')")
@RequestMapping(value = ["/breach-notice"], produces = ["application/json"])
class BreachNoticeController(private val breachNoticeService: BreachNoticeService) {
@GetMapping("/{uuid}")
@@ -69,7 +71,7 @@ class BreachNoticeController(private val breachNoticeService: BreachNoticeServic
],
)
@ResponseStatus(HttpStatus.CREATED)
fun createBreachNotice(@RequestBody breachNotice: BreachNotice) = breachNoticeService.createBreachNotice(breachNotice)
fun createBreachNotice(@Valid @RequestBody breachNotice: BreachNotice) = breachNoticeService.createBreachNotice(breachNotice)


@PutMapping("/{id}")
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package uk.gov.justice.digital.hmpps.breachnoticeapi.model

import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.Size
import java.time.LocalDate
import java.time.LocalDateTime

data class BreachNotice(
@field:NotBlank(message = "CRN must not be blank")
@field:Size(min = 7, max = 7 , message ="CRN must be 7 characters long" )
val crn: String,
val titleAndFullName: String? = null,
val dateOfLetter: LocalDate? = null,
8 changes: 8 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -63,3 +63,11 @@ spring.config.activate.on-profile: dev
hmpps-auth.url: http://localhost:8090/auth
database.endpoint: localhost:5432
frontend.url: http://localhost:3000

---
spring.config.activate.on-profile: test
hmpps-auth.url: http://localhost:8090/auth
frontend.url: http://localhost:3000
spring.datasource:
url: jdbc:tc:postgresql:17:///breachdb

10 changes: 0 additions & 10 deletions src/main/resources/db/migration/V1_0__breach_initial_schema.sql
Original file line number Diff line number Diff line change
@@ -26,8 +26,6 @@ CREATE TABLE public.breach_notice(id uuid not null primary key,
warning_details_saved boolean NULL,
next_appointment_saved boolean NULL);

ALTER TABLE public.breach_notice OWNER TO postgres;

CREATE TABLE public.address(id uuid not null primary Key,
type varchar(100) NULL,
building_name varchar(35) NULL,
@@ -42,8 +40,6 @@ CREATE TABLE public.address(id uuid not null primary Key,
last_updated_user varchar(50) not null,
last_updated_datetime timestamp without time zone not null);

ALTER TABLE public.address OWNER TO postgres;

CREATE TABLE public.breach_notice_contact(id uuid not null primary key,
breach_notice_id uuid not null ,
contact_date timestamp without time zone not null,
@@ -55,9 +51,6 @@ CREATE TABLE public.breach_notice_contact(id uuid not null primary key,
last_updated_user varchar(50) not null,
last_updated_datetime timestamp without time zone NULL);

ALTER TABLE public.breach_notice_contact OWNER TO postgres;


CREATE TABLE public.breach_notice_requirement(id uuid not null primary key,
breach_notice_id uuid not null,
requirement_id bigint not null,
@@ -69,9 +62,6 @@ CREATE TABLE public.breach_notice_requirement(id uuid not null primary key,
last_updated_user varchar(50) not null,
last_updated_datetime timestamp without time zone NULL);

ALTER TABLE public.breach_notice_requirement OWNER TO postgres;


ALTER TABLE public.breach_notice_requirement ADD CONSTRAINT xfk1_breach_notice_requirement
FOREIGN KEY (breach_notice_id) REFERENCES public.breach_notice (id) ON DELETE No Action ON UPDATE No Action;

Original file line number Diff line number Diff line change
@@ -7,13 +7,13 @@ import org.junit.jupiter.api.Test
class AuthorisationTest : IntegrationTestBase() {

@Nested
@DisplayName("GET GET /breach-notice-service/breach-notice/{parameter}")
@DisplayName("GET /breach-notice/{parameter}")
inner class BreachNoticeTestEntityEndpoint {

@Test
fun `should return unauthorized if no token`() {
webTestClient.get()
.uri("/breach-notice-service/breach-notice/{parameter}", "b9a037f2-a558-497b-9fb3-840572e3a17d")
.uri("/breach-notice/{parameter}", "b9a037f2-a558-497b-9fb3-840572e3a17d")
.exchange()
.expectStatus()
.isUnauthorized
@@ -22,93 +22,12 @@ class AuthorisationTest : IntegrationTestBase() {
@Test
fun `should return forbidden if no role`() {
webTestClient.get()
.uri("/breach-notice-service/breach-notice/{parameter}", "b9a037f2-a558-497b-9fb3-840572e3a17d")
.uri("/breach-notice/{parameter}", "b9a037f2-a558-497b-9fb3-840572e3a17d")
.headers(setAuthorisation())
.exchange()
.expectStatus()
.isForbidden
}

@Test
fun `should return OK`() {
webTestClient.get()
.uri("/breach-notice-service/breach-notice/{parameter}", "b9a037f2-a558-497b-9fb3-840572e3a17d")
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.exchange()
.expectStatus()
.isOk
// .expectBody()
// .jsonPath("$").value<String> {
// assertThat(it).startsWith("${LocalDate.now()}")
}
}
}

// @Nested
// @DisplayName("GET /breach-notice-service/breach-notice/{parameter}")
// inner class UserDetailsEndpoint {

// @Test
// fun `should return unauthorized if no token`() {
// webTestClient.get()
// .uri("/example/message/{parameter}", "bob")
// .exchange()
// .expectStatus()
// .isUnauthorized
// }

// @Test
// fun `should return forbidden if no role`() {
// webTestClient.get()
// .uri("/example/message/{parameter}", "bob")
// .headers(setAuthorisation(roles = listOf()))
// .exchange()
// .expectStatus()
// .isForbidden
// }

// @Test
// fun `should return forbidden if wrong role`() {
// webTestClient.get()
// .uri("/example/message/{parameter}", "bob")
// .headers(setAuthorisation(roles = listOf("ROLE_WRONG")))
// .exchange()
// .expectStatus()
// .isForbidden
// }

// @Test
// fun `should return OK`() {
// hmppsAuth.stubGrantToken()
// exampleApi.stubExampleExternalApiUserMessage()
// webTestClient.get()
// .uri("/example/message/{parameter}", "bob")
// .headers(setAuthorisation(username = "AUTH_OK", roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
// .exchange()
// .expectStatus()
// .isOk
// .expectBody()
// .jsonPath("$.message").isEqualTo("A stubbed message")
//
// exampleApi.verify(WireMock.getRequestedFor(WireMock.urlEqualTo("/example-external-api/bob")))
// hmppsAuth.verify(1, WireMock.postRequestedFor(WireMock.urlEqualTo("/auth/oauth/token")))
// }

// @Test
// fun `should return empty response if user not found`() {
// hmppsAuth.stubGrantToken()
// exampleApi.stubExampleExternalApiNotFound()
// webTestClient.get()
// .uri("/example/message/{parameter}", "bob")
// .headers(setAuthorisation(username = "AUTH_NOTFOUND", roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
// .exchange()
// .expectStatus()
// .isOk
// .expectBody()
// .jsonPath("$.message").doesNotExist()
//
// exampleApi.verify(WireMock.getRequestedFor(WireMock.urlEqualTo("/example-external-api/bob")))
// hmppsAuth.verify(1, WireMock.postRequestedFor(WireMock.urlEqualTo("/auth/oauth/token")))
// }
// }
// }

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package uk.gov.justice.digital.hmpps.breachnoticeapi.integration

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import uk.gov.justice.digital.hmpps.breachnoticeapi.entity.BreachNoticeEntity
import uk.gov.justice.digital.hmpps.breachnoticeapi.model.BreachNotice
import uk.gov.justice.digital.hmpps.breachnoticeapi.repository.BreachNoticeRepository
import java.time.LocalDate
import java.time.LocalDateTime

class BreachNoticeCrudTests : IntegrationTestBase() {

@Autowired
private lateinit var breachNoticeRepository: BreachNoticeRepository

@Test
fun `should create a breach notice`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.bodyValue(
BreachNotice(
crn = "X00000B",
),
)
.exchange()
.expectStatus()
.isCreated

var breachNotice: MutableList<BreachNoticeEntity> = breachNoticeRepository.findByCrn("X00000B")
assertThat(breachNotice).hasSize(1)
assertThat(breachNotice.first().crn).isEqualTo("X00000B")
assertThat(breachNotice.first().id).isNotNull()
}

@Test
fun `should update a breach notice`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.bodyValue(
BreachNotice(
crn = "X00001B",
),
)
.exchange()
.expectStatus()
.isCreated

var breachNotice: MutableList<BreachNoticeEntity> = breachNoticeRepository.findByCrn("X00001B")
assertThat(breachNotice).hasSize(1)
assertThat(breachNotice.first().crn).isEqualTo("X00001B")

webTestClient.put()
.uri("/breach-notice/"+breachNotice.first().id)
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.bodyValue(
BreachNotice(
crn = "X00001B",
breachConditionTypeCode = "TYPE_CODE",
titleAndFullName = "Mr Joe Bloggs",
dateOfLetter = LocalDate.now(),
referenceNumber = "REFERENCE_NUMBER",
responseRequiredDate = LocalDate.now(),
breachNoticeTypeCode = "BRCH",
responsibleOfficer = "John Doe",
contactNumber = "01912525252",
nextAppointmentType = "NXTTYP",
nextAppointmentDate = LocalDateTime.now(),
nextAppointmentLocation = "NXT_LOCATION",
nextAppointmentOfficer = "APPT_OFFICER",
nextAppointmentContact = null,
completedDate = LocalDateTime.now(),
offenderAddress = null,
replyAddress = null,
basicDetailsSaved = true,
),
)
.exchange()
.expectStatus()
.isOk

var updatedBreachNotice: MutableList<BreachNoticeEntity> = breachNoticeRepository.findByCrn("X00001B")
assertThat(updatedBreachNotice).hasSize(1)
assertThat(updatedBreachNotice.first().crn).isEqualTo("X00001B")
assertThat(updatedBreachNotice.first().nextAppointmentLocation).isEqualTo("NXT_LOCATION")
assertThat(updatedBreachNotice.first().responsibleOfficer).isEqualTo("John Doe")
assertThat(updatedBreachNotice.first().basicDetailsSaved).isEqualTo(true)
}

@Test
fun `should fail to create if the crn is too long`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.bodyValue(
BreachNotice(
crn = "X00000B123456789123456",
),
)
.exchange()
.expectStatus()
.is5xxServerError
}

@Test
fun `should fail to create if the crn is too short`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_TEMPLATE_KOTLIN__UI")))
.bodyValue(
BreachNotice(
crn = "X",
),
)
.exchange()
.expectStatus()
.is5xxServerError
}
}
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.breachnoticeapi.integration
import io.swagger.v3.parser.OpenAPIV3Parser
import net.minidev.json.JSONArray
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource
@@ -63,6 +64,7 @@ class OpenApiDocsTest : IntegrationTestBase() {
}

@Test
@Disabled
fun `the open api json path security requirements are valid`() {
val result = OpenAPIV3Parser().readLocation("http://localhost:$port/v3/api-docs", null, null)

Loading