diff --git a/apps/judicial-system/backend/infra/judicial-system-backend.ts b/apps/judicial-system/backend/infra/judicial-system-backend.ts index 8d8fb88fcd95..1445073f9aa3 100644 --- a/apps/judicial-system/backend/infra/judicial-system-backend.ts +++ b/apps/judicial-system/backend/infra/judicial-system-backend.ts @@ -74,6 +74,8 @@ export const serviceSetup = (): ServiceBuilder<'judicial-system-backend'> => PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL', PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS', + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: + '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL', AUTH_JWT_SECRET: '/k8s/judicial-system/AUTH_JWT_SECRET', ADMIN_USERS: '/k8s/judicial-system/ADMIN_USERS', BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN', diff --git a/apps/judicial-system/backend/src/app/messages/notifications.ts b/apps/judicial-system/backend/src/app/messages/notifications.ts index ed00262e39d9..5ffd4e6bbfcd 100644 --- a/apps/judicial-system/backend/src/app/messages/notifications.ts +++ b/apps/judicial-system/backend/src/app/messages/notifications.ts @@ -781,6 +781,11 @@ export const notifications = { defaultMessage: 'Landsréttur', description: 'Nafn á Landsrétti í tölvupóstum', }, + publicProsecutorCriminalRecords: { + id: 'judicial.system.backend:notifications.email_names.public_prosecutor_criminal_records', + defaultMessage: 'Ritari sakaskrár', + description: 'Nafn á ritara sakaskrá í tölvupóstum', + }, }), COAJudgeAssigned: defineMessages({ subject: { diff --git a/apps/judicial-system/backend/src/app/modules/notification/notification.config.ts b/apps/judicial-system/backend/src/app/modules/notification/notification.config.ts index e91cc08bd354..05e1bd9a9ac5 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/notification.config.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/notification.config.ts @@ -18,6 +18,10 @@ export const notificationModuleConfig = defineConfig({ 'PRISON_ADMIN_INDICTMENT_EMAILS', '', ), + publicProsecutorCriminalRecordsEmail: env.required( + 'PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL', + '', + ), courtsEmails: env.requiredJSON('COURTS_EMAILS', {}) as { [key: string]: string }, diff --git a/apps/judicial-system/backend/src/app/modules/notification/notificationDispatch.service.ts b/apps/judicial-system/backend/src/app/modules/notification/notificationDispatch.service.ts index dbaff1fd065d..c3c809c2a400 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/notificationDispatch.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/notificationDispatch.service.ts @@ -3,12 +3,12 @@ import { Injectable, InternalServerErrorException, } from '@nestjs/common' -import { ConfigType } from '@nestjs/config' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import { MessageService, MessageType } from '@island.is/judicial-system/message' import { + CaseFileCategory, EventNotificationType, IndictmentCaseNotificationType, InstitutionNotificationType, @@ -71,7 +71,7 @@ export class NotificationDispatchService { private async dispatchIndictmentSentToPublicProsecutorNotifications( theCase: Case, ): Promise { - return this.messageService.sendMessagesToQueue([ + const messages = [ { type: MessageType.INDICTMENT_CASE_NOTIFICATION, caseId: theCase.id, @@ -79,7 +79,20 @@ export class NotificationDispatchService { type: IndictmentCaseNotificationType.INDICTMENT_VERDICT_INFO, }, }, - ]) + ] + const hasCriminalRecordFiles = theCase.caseFiles?.some( + (file) => file.category === CaseFileCategory.CRIMINAL_RECORD_UPDATE, + ) + if (hasCriminalRecordFiles) { + messages.push({ + type: MessageType.INDICTMENT_CASE_NOTIFICATION, + caseId: theCase.id, + body: { + type: IndictmentCaseNotificationType.CRIMINAL_RECORD_FILES_UPLOADED, + }, + }) + } + return this.messageService.sendMessagesToQueue(messages) } async dispatchEventNotification( diff --git a/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.service.ts index 821662fa0ca0..b44322fda25d 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.service.ts @@ -10,12 +10,13 @@ import { EmailService } from '@island.is/email-service' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import { type ConfigType } from '@island.is/nest/config' +import { ROUTE_HANDLER_ROUTE } from '@island.is/judicial-system/consts' import { CaseIndictmentRulingDecision, IndictmentCaseNotificationType, - IndictmentDecision, } from '@island.is/judicial-system/types' +import { notifications } from '../../../../messages' import { Case } from '../../../case' import { EventService } from '../../../event' import { BaseNotificationService } from '../../baseNotification.service' @@ -124,6 +125,42 @@ export class IndictmentCaseNotificationService extends BaseNotificationService { ) } + private async sendCriminalRecordFilesUploadedNotification( + theCase: Case, + ): Promise { + const formattedSubject = this.formatMessage( + strings.criminalRecordFilesUploadedEmail.subject, + { + courtCaseNumber: theCase.courtCaseNumber, + }, + ) + + const formattedBody = this.formatMessage( + strings.criminalRecordFilesUploadedEmail.body, + { + courtCaseNumber: theCase.courtCaseNumber, + courtName: theCase.court?.name.replace('dómur', 'dómi'), + linkStart: ``, + linkEnd: '', + }, + ) + + return this.sendEmails( + theCase, + IndictmentCaseNotificationType.CRIMINAL_RECORD_FILES_UPLOADED, + formattedSubject, + formattedBody, + [ + { + name: this.formatMessage( + notifications.emailNames.publicProsecutorCriminalRecords, + ), + email: this.config.email.publicProsecutorCriminalRecordsEmail, + }, + ], + ) + } + private sendNotification( notificationType: IndictmentCaseNotificationType, theCase: Case, @@ -131,6 +168,8 @@ export class IndictmentCaseNotificationService extends BaseNotificationService { switch (notificationType) { case IndictmentCaseNotificationType.INDICTMENT_VERDICT_INFO: return this.sendVerdictInfoNotification(theCase) + case IndictmentCaseNotificationType.CRIMINAL_RECORD_FILES_UPLOADED: + return this.sendCriminalRecordFilesUploadedNotification(theCase) default: throw new InternalServerErrorException( diff --git a/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.strings.ts b/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.strings.ts index c9ed5ec52513..71dd26bfecd1 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.strings.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/services/indictmentCaseNotification/indictmentCaseNotification.strings.ts @@ -16,4 +16,19 @@ export const strings = { 'Notað sem body í tilkynningu um stöðu birtingar dóms í lokinni ákæru', }, }), + criminalRecordFilesUploadedEmail: defineMessages({ + subject: { + id: 'judicial.system.backend:notifications.criminal_record_files_uploaded_email.subject', + defaultMessage: 'Tilkynning til sakaskrár í máli {courtCaseNumber}', + description: + 'Fyrirsögn í pósti til ritara sakaskrá þegar skjal fyrir tilkynningu til skakaskrár er hlaðið upp', + }, + body: { + id: 'judicial.system.backend:notifications.criminal_record_files_uploaded_email.body', + defaultMessage: + 'Máli {courtCaseNumber} hjá {courtName} hefur verið lokið. Skjöl málsins eru aðgengileg á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}', + description: + 'Texti í pósti til ritara sakaskrá þegar skjal fyrir tilkynningu til skakaskrár er hlaðið upp', + }, + }), } diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/eventNotificationDispatch/eventNotificationDispatch.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/eventNotificationDispatch/eventNotificationDispatch.spec.ts index 490b135e8429..65ada891562b 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/eventNotificationDispatch/eventNotificationDispatch.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/eventNotificationDispatch/eventNotificationDispatch.spec.ts @@ -2,6 +2,7 @@ import { uuid } from 'uuidv4' import { MessageService, MessageType } from '@island.is/judicial-system/message' import { + CaseFileCategory, EventNotificationType, IndictmentCaseNotificationType, } from '@island.is/judicial-system/types' @@ -9,10 +10,19 @@ import { import { createTestingNotificationModule } from '../../createTestingNotificationModule' import { Case } from '../../../../case' +import { CaseFile } from '../../../../file' import { InternalNotificationController } from '../../../internalNotification.controller' describe('InternalNotificationController - Dispatch event notifications', () => { - const theCase = { id: uuid() } as Case + const theCase = { + id: uuid(), + caseFiles: [ + { + category: CaseFileCategory.CRIMINAL_RECORD_UPDATE, + }, + ] as CaseFile[], + } as Case + let mockMessageService: MessageService let internalNotificationController: InternalNotificationController @@ -32,23 +42,32 @@ describe('InternalNotificationController - Dispatch event notifications', () => { notificationType: EventNotificationType.INDICTMENT_SENT_TO_PUBLIC_PROSECUTOR, - expectedMessage: { - type: MessageType.INDICTMENT_CASE_NOTIFICATION, - caseId: theCase.id, - body: { - type: IndictmentCaseNotificationType.INDICTMENT_VERDICT_INFO, + expectedMessages: [ + { + type: MessageType.INDICTMENT_CASE_NOTIFICATION, + caseId: theCase.id, + body: { + type: IndictmentCaseNotificationType.INDICTMENT_VERDICT_INFO, + }, }, - }, + { + type: MessageType.INDICTMENT_CASE_NOTIFICATION, + caseId: theCase.id, + body: { + type: IndictmentCaseNotificationType.CRIMINAL_RECORD_FILES_UPLOADED, + }, + }, + ], }, ] it.each( - notificationScenarios.map(({ notificationType, expectedMessage }) => ({ + notificationScenarios.map(({ notificationType, expectedMessages }) => ({ notificationType, - expectedMessage, - description: `should send message to queue for notification type ${notificationType}`, + expectedMessages, + description: `should send messages to queue for notification type ${notificationType}`, })), - )('$description', async ({ notificationType, expectedMessage }) => { + )('$description', async ({ notificationType, expectedMessages }) => { const result = await internalNotificationController.dispatchEventNotification( theCase.id, @@ -56,9 +75,9 @@ describe('InternalNotificationController - Dispatch event notifications', () => { type: notificationType }, ) - expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([ - expectedMessage, - ]) + expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith( + expectedMessages, + ) expect(result).toEqual({ delivered: true }) }) diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/indictmentCaseNotification/sendIndictmentCriminalRecordFilesUploadedNotification.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/indictmentCaseNotification/sendIndictmentCriminalRecordFilesUploadedNotification.spec.ts new file mode 100644 index 000000000000..5f097dc9a952 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/indictmentCaseNotification/sendIndictmentCriminalRecordFilesUploadedNotification.spec.ts @@ -0,0 +1,93 @@ +import { uuid } from 'uuidv4' + +import { EmailService } from '@island.is/email-service' +import { ConfigType } from '@island.is/nest/config' + +import { IndictmentCaseNotificationType } from '@island.is/judicial-system/types' + +import { createTestingNotificationModule } from '../../createTestingNotificationModule' + +import { Case } from '../../../../case' +import { DeliverResponse } from '../../../models/deliver.response' +import { notificationModuleConfig } from '../../../notification.config' + +interface Then { + result: DeliverResponse + error: Error +} + +type GivenWhenThen = ( + theCase: Case, + notificationType: IndictmentCaseNotificationType, +) => Promise + +describe('IndictmentCaseService', () => { + const caseId = uuid() + const courtName = uuid() + + const courtCaseNumber = uuid() + const theCase = { + id: caseId, + court: { name: courtName }, + courtCaseNumber, + } as Case + + let mockEmailService: EmailService + let mockConfig: ConfigType + let givenWhenThen: GivenWhenThen + + beforeEach(async () => { + process.env.PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL = + 'publicProsecutor@omnitrix.is' + + const { + emailService, + notificationConfig, + indictmentCaseNotificationService, + } = await createTestingNotificationModule() + + mockEmailService = emailService + mockConfig = notificationConfig + + givenWhenThen = async ( + theCase: Case, + notificationType: IndictmentCaseNotificationType, + ) => { + const then = {} as Then + + await indictmentCaseNotificationService + .sendIndictmentCaseNotification(notificationType, theCase) + .then((result) => (then.result = result)) + .catch((error) => (then.error = error)) + + return then + } + }) + + describe('notification sent to public prosecutor criminal records secretary', () => { + it('should send notification', async () => { + const then = await givenWhenThen( + theCase, + IndictmentCaseNotificationType.CRIMINAL_RECORD_FILES_UPLOADED, + ) + + expect(mockEmailService.sendEmail).toBeCalledWith( + expect.objectContaining({ + to: [ + { + name: 'Ritari sakaskrár', + address: mockConfig.email.publicProsecutorCriminalRecordsEmail, + }, + ], + subject: expect.stringContaining( + `Tilkynning til sakaskrár í máli ${courtCaseNumber}`, + ), + html: expect.stringContaining( + `Máli ${courtCaseNumber} hjá ${courtName} hefur verið lokið.`, + ), + }), + ) + expect(then.result).toEqual({ delivered: true }) + }) + }) +}) diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index c5d0f700d69b..5b30d8befc2d 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -229,6 +229,7 @@ judicial-system-backend: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index e0747b1254c4..5bb64cbc525e 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -229,6 +229,7 @@ judicial-system-backend: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index 6939b5a9fae4..b0fcf242d102 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -229,6 +229,7 @@ judicial-system-backend: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/charts/services/judicial-system-backend/values.dev.yaml b/charts/services/judicial-system-backend/values.dev.yaml index df2ab994c0bc..4245d84aee6a 100644 --- a/charts/services/judicial-system-backend/values.dev.yaml +++ b/charts/services/judicial-system-backend/values.dev.yaml @@ -142,6 +142,7 @@ secrets: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/charts/services/judicial-system-backend/values.prod.yaml b/charts/services/judicial-system-backend/values.prod.yaml index d0047fef3de8..d01b03785133 100644 --- a/charts/services/judicial-system-backend/values.prod.yaml +++ b/charts/services/judicial-system-backend/values.prod.yaml @@ -142,6 +142,7 @@ secrets: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/charts/services/judicial-system-backend/values.staging.yaml b/charts/services/judicial-system-backend/values.staging.yaml index a4c0268de4d4..ab1ee2768e71 100644 --- a/charts/services/judicial-system-backend/values.staging.yaml +++ b/charts/services/judicial-system-backend/values.staging.yaml @@ -142,6 +142,7 @@ secrets: PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL' PRISON_ADMIN_INDICTMENT_EMAILS: '/k8s/judicial-system/PRISON_ADMIN_INDICTMENT_EMAILS' PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL' + PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL: '/k8s/judicial-system/PUBLIC_PROSECUTOR_CRIMINAL_RECORDS_EMAIL' XROAD_CLIENT_CERT: '/k8s/judicial-system/XROAD_CLIENT_CERT' XROAD_CLIENT_KEY: '/k8s/judicial-system/XROAD_CLIENT_KEY' XROAD_CLIENT_PEM: '/k8s/judicial-system/XROAD_CLIENT_PEM' diff --git a/libs/judicial-system/types/src/lib/notification.ts b/libs/judicial-system/types/src/lib/notification.ts index ee863976b056..e012dad8237c 100644 --- a/libs/judicial-system/types/src/lib/notification.ts +++ b/libs/judicial-system/types/src/lib/notification.ts @@ -24,6 +24,7 @@ export enum CaseNotificationType { export enum IndictmentCaseNotificationType { INDICTMENT_VERDICT_INFO = 'INDICTMENT_VERDICT_INFO', + CRIMINAL_RECORD_FILES_UPLOADED = 'CRIMINAL_RECORD_FILES_UPLOADED', } export enum DefendantNotificationType {