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

feat(j-s): Create ruling confirmation #15894

Merged
merged 28 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7e753df
Checkpoint
oddsson Sep 3, 2024
8c70712
Cleanup
oddsson Sep 3, 2024
0609609
Rename
oddsson Sep 3, 2024
94272e3
Refactor
oddsson Sep 3, 2024
7243691
Remove unused code
oddsson Sep 4, 2024
9372871
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 4, 2024
c2c1c8c
Fix lint
oddsson Sep 4, 2024
4e59633
Create confirmed ruling
oddsson Sep 4, 2024
f80169d
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 4, 2024
681d3ec
Create confirmed ruling
oddsson Sep 4, 2024
e386846
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 4, 2024
5fb3982
Make confirmation smaller
oddsson Sep 4, 2024
583bc17
Make confirmation smaller
oddsson Sep 4, 2024
6df6cce
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 4, 2024
60732f3
Use correct date
oddsson Sep 4, 2024
d1849ec
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 4, 2024
d69086f
Merge branch 'j-s/confirmed-subpoena' of github.com:island-is/island.…
oddsson Sep 4, 2024
6f6c878
Merge
oddsson Sep 4, 2024
3b7b575
Refactor
oddsson Sep 5, 2024
c46d228
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 5, 2024
0569711
Refactor
oddsson Sep 5, 2024
2deea1f
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 9, 2024
514f110
Cleanup
oddsson Sep 9, 2024
d53b489
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 9, 2024
dbd47c6
Merge branch 'main' of github.com:island-is/island.is into j-s/confir…
oddsson Sep 9, 2024
dcd10f9
Cleanup
oddsson Sep 9, 2024
e2a7d6a
Check for completed cases
oddsson Sep 9, 2024
6de5730
Merge branch 'main' into j-s/confirmed-ruling
kodiakhq[bot] Sep 10, 2024
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib'

import { formatDate, lowercase } from '@island.is/judicial-system/formatters'
import { CaseFileCategory } from '@island.is/judicial-system/types'

import {
calculatePt,
Expand All @@ -10,46 +11,48 @@ import {
} from './pdfHelpers'
import { PDFKitCoatOfArms } from './PDFKitCoatOfArms'

export const createConfirmedIndictment = async (
// Colors
const lightGray = rgb(0.9804, 0.9804, 0.9804)
const darkGray = rgb(0.7961, 0.7961, 0.7961)
const gold = rgb(0.6784, 0.6392, 0.451)
const white = rgb(1, 1, 1)

// Spacing
const pageMargin = calculatePt(18)
const coatOfArmsX = pageMargin + calculatePt(8)
const coatOfArmsWidth = calculatePt(105)
const confirmedByHeight = calculatePt(50)
const titleX = coatOfArmsX + coatOfArmsWidth + calculatePt(8)

const createIndictmentConfirmation = async (
confirmation: Confirmation,
indictmentPDF: Buffer,
): Promise<Buffer> => {
const pdfDoc = await PDFDocument.load(indictmentPDF)
pdfDoc: PDFDocument,
) => {
const pages = pdfDoc.getPages()
const doc = pages[0]

const lightGray = rgb(0.9804, 0.9804, 0.9804)
const darkGray = rgb(0.7961, 0.7961, 0.7961)
const gold = rgb(0.6784, 0.6392, 0.451)
const white = rgb(1, 1, 1)
const shadowHeight = calculatePt(90)
const { width, height } = doc.getSize()
const pageMargin = calculatePt(18)
const shaddowHeight = calculatePt(90)
const coatOfArmsWidth = calculatePt(105)
const coatOfArmsHeight = calculatePt(90)
const coatOfArmsX = pageMargin + calculatePt(8)
const titleWidth = width - coatOfArmsWidth - 2 * coatOfArmsX
const titleHeight = calculatePt(32)
const titleX = coatOfArmsX + coatOfArmsWidth + calculatePt(8)
const titleWidth = width - coatOfArmsWidth - 2 * coatOfArmsX
const confirmedByWidth = calculatePt(258)
const confirmedByHeight = calculatePt(50)
const institutionWidth = confirmedByWidth + calculatePt(48)

// Draw the shaddow
// Draw the shadow
doc.drawRectangle({
x: pageMargin,
y: height - shaddowHeight - pageMargin,
y: height - shadowHeight - pageMargin,
width: doc.getWidth() - 2 * pageMargin - calculatePt(16),
height: shaddowHeight,
height: shadowHeight,
color: lightGray,
})

// Draw the box around the coat of arms
doc.drawRectangle({
x: coatOfArmsX,
y: height - shaddowHeight - pageMargin + calculatePt(8),
y: height - shadowHeight - pageMargin + calculatePt(8),
width: coatOfArmsWidth,
height: coatOfArmsHeight,
height: shadowHeight,
color: rgb(1, 1, 1),
borderColor: darkGray,
borderWidth: 1,
Expand Down Expand Up @@ -99,7 +102,7 @@ export const createConfirmedIndictment = async (
x: coatOfArmsX + coatOfArmsWidth,
y: height - pageMargin - titleHeight - confirmedByHeight,
width: confirmedByWidth,
height: shaddowHeight - titleHeight,
height: shadowHeight - titleHeight,
color: white,
borderColor: darkGray,
borderWidth: 1,
Expand Down Expand Up @@ -136,7 +139,7 @@ export const createConfirmedIndictment = async (
x: coatOfArmsX + coatOfArmsWidth + confirmedByWidth,
y: height - pageMargin - titleHeight - confirmedByHeight,
width: institutionWidth,
height: shaddowHeight - titleHeight,
height: shadowHeight - titleHeight,
color: white,
borderColor: darkGray,
borderWidth: 1,
Expand All @@ -163,7 +166,7 @@ export const createConfirmedIndictment = async (
x: width - 90,
y: height - pageMargin - titleHeight - confirmedByHeight,
width: 70,
height: shaddowHeight - titleHeight,
height: shadowHeight - titleHeight,
color: white,
borderColor: darkGray,
borderWidth: 1,
Expand All @@ -188,8 +191,160 @@ export const createConfirmedIndictment = async (
})
}
}
}

const pdfBytes = await pdfDoc.save()
const createRulingConfirmation = async (
confirmation: Confirmation,
pdfDoc: PDFDocument,
) => {
const pages = pdfDoc.getPages()
const doc = pages[0]

const { height } = doc.getSize()
const shaddowHeight = calculatePt(70)
const institutionWidth = calculatePt(160)
const confirmedByWidth = institutionWidth + calculatePt(48)
const shaddowWidth = institutionWidth + confirmedByWidth + coatOfArmsWidth
const titleHeight = calculatePt(24)
const titleWidth = institutionWidth + confirmedByWidth

// Draw the shadow
doc.drawRectangle({
x: pageMargin,
y: height - shaddowHeight - pageMargin,
width: shaddowWidth,
height: shaddowHeight,
color: lightGray,
})

// Draw the box around the coat of arms
doc.drawRectangle({
x: coatOfArmsX,
y: height - shaddowHeight - pageMargin + calculatePt(8),
width: coatOfArmsWidth,
height: shaddowHeight,
color: rgb(1, 1, 1),
borderColor: darkGray,
borderWidth: 1,
})

PDFKitCoatOfArms(doc, height + 8)

doc.drawRectangle({
x: coatOfArmsX + coatOfArmsWidth,
y: height - pageMargin - titleHeight + calculatePt(8),
width: titleWidth,
height: titleHeight,
color: lightGray,
borderColor: darkGray,
borderWidth: 1,
})

const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman)
const timesRomanBoldFont = await pdfDoc.embedFont(
StandardFonts.TimesRomanBold,
)
doc.drawText('Réttarvörslugátt', {
x: titleX,
y: height - pageMargin - titleHeight + calculatePt(16),
size: calculatePt(smallFontSize),
font: timesRomanBoldFont,
})

doc.drawText('Rafræn staðfesting', {
x: 158,
y: height - pageMargin - titleHeight + calculatePt(16),
size: calculatePt(smallFontSize),
font: timesRomanFont,
})

doc.drawText(formatDate(confirmation.date) || '', {
x: shaddowWidth - calculatePt(24),
y: height - pageMargin - titleHeight + calculatePt(16),
size: calculatePt(smallFontSize),
font: timesRomanFont,
})

// Draw the "Institution" box
doc.drawRectangle({
x: coatOfArmsX + coatOfArmsWidth,
y: height - pageMargin - titleHeight - confirmedByHeight + calculatePt(12),
width: institutionWidth,
height: shaddowHeight - titleHeight,
color: white,
borderColor: darkGray,
borderWidth: 1,
})

doc.drawText('Dómstóll', {
x: titleX,
y: height - pageMargin - titleHeight - calculatePt(10),
size: calculatePt(smallFontSize),
font: timesRomanBoldFont,
})

if (confirmation?.institution) {
doc.drawText(confirmation.institution, {
x: titleX,
y: height - pageMargin - titleHeight - calculatePt(22),
font: timesRomanFont,
size: calculatePt(smallFontSize),
})
}

// Draw the "Institution" box
doc.drawRectangle({
x: coatOfArmsX + coatOfArmsWidth + institutionWidth,
y: height - pageMargin - titleHeight - confirmedByHeight + calculatePt(12),
width: confirmedByWidth,
height: shaddowHeight - titleHeight,
color: white,
borderColor: darkGray,
borderWidth: 1,
})

doc.drawText('Samþykktaraðili', {
x: titleX + institutionWidth,
y: height - pageMargin - titleHeight - calculatePt(10),
size: calculatePt(smallFontSize),
font: timesRomanBoldFont,
})

if (confirmation?.actor) {
timesRomanFont.widthOfTextAtSize(
`${confirmation.actor}${
confirmation.title ? `, ${lowercase(confirmation.title)}` : ''
}`,
calculatePt(smallFontSize),
)
drawTextWithEllipsisPDFKit(
doc,
`${confirmation.actor}${
confirmation.title ? `, ${lowercase(confirmation.title)}` : ''
}`,
{ type: timesRomanFont, size: calculatePt(smallFontSize) },
titleX + institutionWidth,
height - pageMargin - titleHeight - calculatePt(22),
confirmedByWidth - 16,
)
}
}
oddsson marked this conversation as resolved.
Show resolved Hide resolved

export const createConfirmedPdf = async (
confirmation: Confirmation,
pdf: Buffer,
fileType: CaseFileCategory.INDICTMENT | CaseFileCategory.RULING,
) => {
const pdfDoc = await PDFDocument.load(pdf)

if (fileType === CaseFileCategory.INDICTMENT) {
await createIndictmentConfirmation(confirmation, pdfDoc)
}

if (fileType === CaseFileCategory.RULING) {
await createRulingConfirmation(confirmation, pdfDoc)
}

const pdfBytes = await pdfDoc.save()
return Buffer.from(pdfBytes)
}
2 changes: 1 addition & 1 deletion apps/judicial-system/backend/src/app/formatters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ export { getRequestPdfAsBuffer, getRequestPdfAsString } from './requestPdf'
export { getRulingPdfAsBuffer, getRulingPdfAsString } from './rulingPdf'
export { createCaseFilesRecord } from './caseFilesRecordPdf'
export { createIndictment } from './indictmentPdf'
export { createConfirmedIndictment } from './confirmedIndictmentPdf'
export { createConfirmedPdf } from './confirmedPdf'
export { createSubpoena } from './subpoenaPdf'
93 changes: 67 additions & 26 deletions apps/judicial-system/backend/src/app/modules/file/file.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import {
CaseFileState,
EventType,
hasIndictmentCaseBeenSubmittedToCourt,
isCompletedCase,
isIndictmentCase,
} from '@island.is/judicial-system/types'

import { createConfirmedIndictment } from '../../formatters'
import { createConfirmedPdf } from '../../formatters'
import { AwsS3Service } from '../aws-s3'
import { Case } from '../case'
import { CourtDocumentFolder, CourtService } from '../court'
Expand Down Expand Up @@ -181,18 +182,42 @@ export class FileService {

return this.userService
.findByNationalId(confirmationEvent.nationalId)
.then((user) =>
createConfirmedIndictment(
{
actor: user.name,
title: user.title,
institution: user.institution?.name ?? '',
date: confirmationEvent.created,
},
pdf,
),
)
.then((user) => {
if (file.category === CaseFileCategory.INDICTMENT) {
return createConfirmedPdf(
{
actor: user.name,
title: user.title,
institution: user.institution?.name ?? '',
date: confirmationEvent.created,
},
pdf,
CaseFileCategory.INDICTMENT,
)
}

if (
file.category === CaseFileCategory.RULING &&
isCompletedCase(theCase.state) &&
theCase.rulingDate
) {
return createConfirmedPdf(
{
actor: theCase.judge?.name ?? '',
title: theCase.judge?.title,
institution: theCase.judge?.institution?.name ?? '',
date: theCase.rulingDate,
},
pdf,
CaseFileCategory.RULING,
)
}
})
.then((confirmedPdf) => {
if (!confirmedPdf) {
throw new Error('Failed to create confirmed PDF')
}

const binaryPdf = confirmedPdf.toString('binary')
const hash = CryptoJS.MD5(binaryPdf).toString(CryptoJS.enc.Hex)

Expand All @@ -212,18 +237,32 @@ export class FileService {
}

async getCaseFileFromS3(theCase: Case, file: CaseFile): Promise<Buffer> {
if (
isIndictmentCase(theCase.type) &&
hasIndictmentCaseBeenSubmittedToCourt(theCase.state) &&
file.category === CaseFileCategory.INDICTMENT
) {
return this.awsS3Service.getConfirmedIndictmentCaseObject(
theCase.type,
file.key,
!file.hash,
(content: Buffer) =>
this.confirmIndictmentCaseFile(theCase, file, content),
)
if (isIndictmentCase(theCase.type)) {
if (
file.category === CaseFileCategory.INDICTMENT &&
hasIndictmentCaseBeenSubmittedToCourt(theCase.state)
) {
return this.awsS3Service.getConfirmedIndictmentCaseObject(
theCase.type,
file.key,
!file.hash,
(content: Buffer) =>
this.confirmIndictmentCaseFile(theCase, file, content),
)
}

if (
file.category === CaseFileCategory.RULING &&
isCompletedCase(theCase.state)
) {
return this.awsS3Service.getConfirmedIndictmentCaseObject(
theCase.type,
file.key,
!file.hash,
(content: Buffer) =>
this.confirmIndictmentCaseFile(theCase, file, content),
)
}
}

return this.awsS3Service.getObject(theCase.type, file.key)
Expand Down Expand Up @@ -359,8 +398,10 @@ export class FileService {
): Promise<string> {
if (
isIndictmentCase(theCase.type) &&
hasIndictmentCaseBeenSubmittedToCourt(theCase.state) &&
file.category === CaseFileCategory.INDICTMENT
((file.category === CaseFileCategory.INDICTMENT &&
hasIndictmentCaseBeenSubmittedToCourt(theCase.state)) ||
(file.category === CaseFileCategory.RULING &&
isCompletedCase(theCase.state)))
) {
return this.awsS3Service.getConfirmedIndictmentCaseSignedUrl(
theCase.type,
Expand Down
Loading