diff --git a/apps/judicial-system/backend/migrations/20241003213354-update-notification.js b/apps/judicial-system/backend/migrations/20241003213354-update-notification.js new file mode 100644 index 000000000000..6447e4b170c3 --- /dev/null +++ b/apps/judicial-system/backend/migrations/20241003213354-update-notification.js @@ -0,0 +1,66 @@ +'use strict' +const replaceEnum = require('sequelize-replace-enum-postgres').default + +module.exports = { + up: (queryInterface) => { + // replaceEnum does not support transactions + return replaceEnum({ + queryInterface, + tableName: 'notification', + columnName: 'type', + newValues: [ + 'HEADS_UP', + 'READY_FOR_COURT', + 'RECEIVED_BY_COURT', + 'COURT_DATE', + 'RULING', + 'MODIFIED', + 'REVOKED', + 'ADVOCATE_ASSIGNED', // Changed value + 'DEFENDANTS_NOT_UPDATED_AT_COURT', + 'APPEAL_TO_COURT_OF_APPEALS', + 'APPEAL_RECEIVED_BY_COURT', + 'APPEAL_STATEMENT', + 'APPEAL_COMPLETED', + 'APPEAL_JUDGES_ASSIGNED', + 'APPEAL_CASE_FILES_UPDATED', + 'APPEAL_WITHDRAWN', + 'INDICTMENT_DENIED', + 'INDICTMENT_RETURNED', + 'INDICTMENTS_WAITING_FOR_CONFIRMATION', + ], + enumName: 'enum_notification_type', + }) + }, + + down: (queryInterface) => { + // replaceEnum does not support transactions + return replaceEnum({ + queryInterface, + tableName: 'notification', + columnName: 'type', + newValues: [ + 'HEADS_UP', + 'READY_FOR_COURT', + 'RECEIVED_BY_COURT', + 'COURT_DATE', + 'RULING', + 'MODIFIED', + 'REVOKED', + 'DEFENDER_ASSIGNED', + 'DEFENDANTS_NOT_UPDATED_AT_COURT', + 'APPEAL_TO_COURT_OF_APPEALS', + 'APPEAL_RECEIVED_BY_COURT', + 'APPEAL_STATEMENT', + 'APPEAL_COMPLETED', + 'APPEAL_JUDGES_ASSIGNED', + 'APPEAL_CASE_FILES_UPDATED', + 'APPEAL_WITHDRAWN', + 'INDICTMENT_DENIED', + 'INDICTMENT_RETURNED', + 'INDICTMENTS_WAITING_FOR_CONFIRMATION', + ], + enumName: 'enum_notification_type', + }) + }, +} diff --git a/apps/judicial-system/backend/src/app/formatters/formatters.ts b/apps/judicial-system/backend/src/app/formatters/formatters.ts index babb0c0da5e6..d48904e27885 100644 --- a/apps/judicial-system/backend/src/app/formatters/formatters.ts +++ b/apps/judicial-system/backend/src/app/formatters/formatters.ts @@ -14,7 +14,11 @@ import { laws, readableIndictmentSubtypes, } from '@island.is/judicial-system/formatters' -import type { Gender, UserRole } from '@island.is/judicial-system/types' +import { + AdvocateType, + Gender, + UserRole, +} from '@island.is/judicial-system/types' import { CaseCustodyRestrictions, CaseLegalProvisions, @@ -664,23 +668,45 @@ export const formatCustodyRestrictions = ( }) } -export const formatDefenderAssignedEmailNotification = ( +export const formatAdvocateAssignedEmailNotification = ( formatMessage: FormatMessage, theCase: Case, + advocateType: AdvocateType, overviewUrl?: string, ): SubjectAndBody => { - const subject = formatMessage(notifications.defenderAssignedEmail.subject, { - court: capitalize(theCase.court?.name ?? ''), - }) - - const body = formatMessage(notifications.defenderAssignedEmail.body, { - defenderHasAccessToRVG: Boolean(overviewUrl), - courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''), - court: theCase.court?.name ?? '', - courtName: theCase.court?.name.replace('dómur', 'dómi') ?? '', - linkStart: ``, - linkEnd: '', - }) + const subject = + advocateType === AdvocateType.DEFENDER + ? formatMessage( + notifications.advocateAssignedEmail.subjectAccessToCaseFiles, + { + court: capitalize(theCase.court?.name ?? ''), + }, + ) + : formatMessage(notifications.advocateAssignedEmail.subjectAccess, { + courtCaseNumber: theCase.courtCaseNumber, + }) + + const body = + advocateType === AdvocateType.DEFENDER + ? formatMessage( + notifications.advocateAssignedEmail.bodyAccessToCaseFiles, + { + defenderHasAccessToRVG: Boolean(overviewUrl), + courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''), + court: theCase.court?.name ?? '', + courtName: theCase.court?.name.replace('dómur', 'dómi') ?? '', + linkStart: ``, + linkEnd: '', + }, + ) + : formatMessage(notifications.advocateAssignedEmail.bodyAccess, { + defenderHasAccessToRVG: Boolean(overviewUrl), + court: theCase.court?.name, + advocateType, + courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''), + linkStart: ``, + linkEnd: '', + }) return { body, subject } } diff --git a/apps/judicial-system/backend/src/app/formatters/index.ts b/apps/judicial-system/backend/src/app/formatters/index.ts index 385f09d8df03..ea9b36ec95ba 100644 --- a/apps/judicial-system/backend/src/app/formatters/index.ts +++ b/apps/judicial-system/backend/src/app/formatters/index.ts @@ -21,7 +21,7 @@ export { formatProsecutorReceivedByCourtSmsNotification, formatDefenderCourtDateLinkEmailNotification, formatDefenderResubmittedToCourtEmailNotification, - formatDefenderAssignedEmailNotification, + formatAdvocateAssignedEmailNotification, formatCourtIndictmentReadyForCourtEmailNotification, formatDefenderRoute, formatDefenderReadyForCourtEmailNotification, diff --git a/apps/judicial-system/backend/src/app/messages/notifications.ts b/apps/judicial-system/backend/src/app/messages/notifications.ts index a8868a3b3595..9777fdd1be49 100644 --- a/apps/judicial-system/backend/src/app/messages/notifications.ts +++ b/apps/judicial-system/backend/src/app/messages/notifications.ts @@ -607,19 +607,31 @@ export const notifications = { 'Notaður sem texti í tölvupósti til verjanda vegna breytingar á lengd gæslu/einangrunar/vistunar þar sem úrskurðað var í einangrun.', }, }), - defenderAssignedEmail: defineMessages({ - subject: { - id: 'judicial.system.backend:notifications.defender_assigned_email.subject', + advocateAssignedEmail: defineMessages({ + subjectAccessToCaseFiles: { + id: 'judicial.system.backend:notifications.defender_assigned_email.subject_access_to_case_files', defaultMessage: '{court} - aðgangur að málsgögnum', description: 'Fyrirsögn í pósti til verjanda þegar hann er skráður á mál.', }, - body: { - id: 'judicial.system.backend:notifications.defender_assigned_email.body_v3', + subjectAccess: { + id: 'judicial.system.backend:notifications.defender_assigned_email.subject_access', + defaultMessage: 'Skráning í máli {courtCaseNumber}', + description: + 'Fyrirsögn í pósti til verjanda þegar hann er skráður á mál.', + }, + bodyAccessToCaseFiles: { + id: 'judicial.system.backend:notifications.defender_assigned_email.body_access_to_case_files', defaultMessage: '{court} hefur skráð þig verjanda í máli {courtCaseNumber}.

{defenderHasAccessToRVG, select, true {Gögn málsins eru aðgengileg á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}} other {Þú getur nálgast gögn málsins hjá {courtName} ef þau hafa ekki þegar verið afhent}}.', description: 'Texti í pósti til verjanda þegar hann er skráður á mál.', }, + bodyAccess: { + id: 'judicial.system.backend:notifications.defender_assigned_email.body_access', + defaultMessage: + '{court} hefur skráð þig {advocateType, select, LAWYER {lögmann einkaréttarkröfuhafa} LEGAL_RIGHTS_PROTECTOR {réttargæslumann einkaréttarkröfuhafa} other {verjanda}} í máli {courtCaseNumber}.

{defenderHasAccessToRVG, select, true {Sjá nánar á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}} other {Þú getur nálgast málið hjá {courtName}.}}.', + description: 'Texti í pósti til verjanda þegar hann er skráður á mál.', + }, }), defendantsNotUpdatedAtCourt: defineMessages({ subject: { diff --git a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts index d79774fedfeb..284c03caf5c1 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts @@ -28,7 +28,7 @@ export const districtCourtJudgeNotificationRule: RolesRule = { dtoField: 'type', dtoFieldValues: [ NotificationType.COURT_DATE, - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, ], } @@ -39,7 +39,7 @@ export const districtCourtRegistrarNotificationRule: RolesRule = { dtoField: 'type', dtoFieldValues: [ NotificationType.COURT_DATE, - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, ], } @@ -50,7 +50,7 @@ export const districtCourtAssistantNotificationRule: RolesRule = { dtoField: 'type', dtoFieldValues: [ NotificationType.COURT_DATE, - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, ], } diff --git a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts index ebce85337c80..7be128ecb9b4 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/internalNotification.service.ts @@ -30,6 +30,7 @@ import { lowercase, } from '@island.is/judicial-system/formatters' import { + AdvocateType, CaseAppealRulingDecision, CaseCustodyRestrictions, CaseDecision, @@ -50,13 +51,13 @@ import { } from '@island.is/judicial-system/types' import { + formatAdvocateAssignedEmailNotification, formatCourtHeadsUpSmsNotification, formatCourtIndictmentReadyForCourtEmailNotification, formatCourtOfAppealJudgeAssignedEmailNotification, formatCourtReadyForCourtSmsNotification, formatCourtResubmittedToCourtSmsNotification, formatCourtRevokedSmsNotification, - formatDefenderAssignedEmailNotification, formatDefenderCourtDateEmailNotification, formatDefenderCourtDateLinkEmailNotification, formatDefenderReadyForCourtEmailNotification, @@ -1518,18 +1519,18 @@ export class InternalNotificationService extends BaseNotificationService { } //#endregion - //#region DEFENDER_ASSIGNED notifications */ - private shouldSendDefenderAssignedNotification( + //#region ADVOCATE_ASSIGNED notifications */ + private shouldSendAdvocateAssignedNotification( theCase: Case, - defenderEmail?: string, + advocateEmail?: string, ): boolean { - if (!defenderEmail) { + if (!advocateEmail) { return false } if (isIndictmentCase(theCase.type)) { const hasSentNotificationBefore = this.hasReceivedNotification( - NotificationType.DEFENDER_ASSIGNED, - defenderEmail, + NotificationType.ADVOCATE_ASSIGNED, + advocateEmail, theCase.notifications, ) @@ -1550,7 +1551,7 @@ export class InternalNotificationService extends BaseNotificationService { [ NotificationType.READY_FOR_COURT, NotificationType.COURT_DATE, - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, ], theCase.defenderEmail, theCase.notifications, @@ -1564,30 +1565,32 @@ export class InternalNotificationService extends BaseNotificationService { return true } - private sendDefenderAssignedNotification( + private sendAdvocateAssignedNotification( theCase: Case, - defenderNationalId?: string, - defenderName?: string, - defenderEmail?: string, + advocateType: AdvocateType, + advocateNationalId?: string, + advocateName?: string, + advocateEmail?: string, ): Promise { - const { subject, body } = formatDefenderAssignedEmailNotification( + const { subject, body } = formatAdvocateAssignedEmailNotification( this.formatMessage, theCase, - defenderNationalId && + advocateType, + advocateNationalId && formatDefenderRoute(this.config.clientUrl, theCase.type, theCase.id), ) return this.sendEmail( subject, body, - defenderName, - defenderEmail, + advocateName, + advocateEmail, undefined, - Boolean(defenderNationalId) === false, + Boolean(advocateNationalId) === false, ) } - private async sendDefenderAssignedNotifications( + private async sendAdvocateAssignedNotifications( theCase: Case, ): Promise { const promises: Promise[] = [] @@ -1597,18 +1600,20 @@ export class InternalNotificationService extends BaseNotificationService { theCase.defendants ?? [], (d: Defendant) => d.defenderEmail, ) + for (const defendant of uniqDefendants) { const { defenderEmail, defenderNationalId, defenderName } = defendant - const shouldSend = this.shouldSendDefenderAssignedNotification( + const shouldSend = this.shouldSendAdvocateAssignedNotification( theCase, defenderEmail, ) if (shouldSend === true) { promises.push( - this.sendDefenderAssignedNotification( + this.sendAdvocateAssignedNotification( theCase, + AdvocateType.DEFENDER, defenderNationalId, defenderName, defenderEmail, @@ -1616,8 +1621,40 @@ export class InternalNotificationService extends BaseNotificationService { ) } } + + if (theCase.civilClaimants) { + for (const civilClaimant of theCase.civilClaimants) { + const { + spokespersonEmail, + spokespersonIsLawyer, + spokespersonName, + spokespersonNationalId, + hasSpokesperson, + } = civilClaimant + + const shouldSend = + this.shouldSendAdvocateAssignedNotification( + theCase, + spokespersonEmail, + ) && hasSpokesperson + + if (shouldSend === true) { + promises.push( + this.sendAdvocateAssignedNotification( + theCase, + spokespersonIsLawyer + ? AdvocateType.LAWYER + : AdvocateType.LEGAL_RIGHTS_PROTECTOR, + spokespersonNationalId, + spokespersonName, + spokespersonEmail, + ), + ) + } + } + } } else if (DateLog.arraignmentDate(theCase.dateLogs)?.date) { - const shouldSend = this.shouldSendDefenderAssignedNotification( + const shouldSend = this.shouldSendAdvocateAssignedNotification( theCase, theCase.defenderEmail, ) @@ -1636,7 +1673,7 @@ export class InternalNotificationService extends BaseNotificationService { return this.recordNotification( theCase.id, - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, recipients, ) } @@ -2528,8 +2565,8 @@ export class InternalNotificationService extends BaseNotificationService { return this.sendModifiedNotifications(theCase, user) case NotificationType.REVOKED: return this.sendRevokedNotifications(theCase) - case NotificationType.DEFENDER_ASSIGNED: - return this.sendDefenderAssignedNotifications(theCase) + case NotificationType.ADVOCATE_ASSIGNED: + return this.sendAdvocateAssignedNotifications(theCase) case NotificationType.DEFENDANTS_NOT_UPDATED_AT_COURT: return this.sendDefendantsNotUpdatedAtCourtNotifications(theCase) case NotificationType.APPEAL_TO_COURT_OF_APPEALS: diff --git a/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts index 8103b1106f14..46665cef3181 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/notification.service.ts @@ -62,7 +62,7 @@ export class NotificationService { // the judge chooses not to send a calendar invitation messages = [ this.getNotificationMessage( - NotificationType.DEFENDER_ASSIGNED, + NotificationType.ADVOCATE_ASSIGNED, user, theCase, ), @@ -72,7 +72,7 @@ export class NotificationService { } break case NotificationType.HEADS_UP: - case NotificationType.DEFENDER_ASSIGNED: + case NotificationType.ADVOCATE_ASSIGNED: case NotificationType.APPEAL_JUDGES_ASSIGNED: case NotificationType.APPEAL_CASE_FILES_UPDATED: messages = [this.getNotificationMessage(type, user, theCase)] diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendDefenderAssignedNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAdvocateAssignedNotifications.spec.ts similarity index 72% rename from apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendDefenderAssignedNotifications.spec.ts rename to apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAdvocateAssignedNotifications.spec.ts index a08f371e4825..097e90d35fa6 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendDefenderAssignedNotifications.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/test/internalNotificationController/sendAdvocateAssignedNotifications.spec.ts @@ -43,6 +43,7 @@ describe('InternalNotificationController - Send defender assigned notifications' let mockConfig: ConfigType let mockNotificationModel: typeof Notification let givenWhenThen: GivenWhenThen + let notificationDTO: CaseNotificationDto beforeEach(async () => { const { @@ -52,6 +53,11 @@ describe('InternalNotificationController - Send defender assigned notifications' internalNotificationController, } = await createTestingNotificationModule() + notificationDTO = { + user: { id: userId } as User, + type: NotificationType.ADVOCATE_ASSIGNED, + } + mockEmailService = emailService mockConfig = notificationConfig mockNotificationModel = notificationModel @@ -78,11 +84,8 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('when sending defender assigned notifications', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() + const defendant = { defenderNationalId: '1234567890', defenderEmail: 'recipient@gmail.com', @@ -97,7 +100,7 @@ describe('InternalNotificationController - Send defender assigned notifications' } as Case beforeEach(async () => { - await givenWhenThen(caseId, theCase, notificationDto) + await givenWhenThen(caseId, theCase, notificationDTO) }) it('should send correct email', () => { @@ -119,17 +122,127 @@ describe('InternalNotificationController - Send defender assigned notifications' }, attachments: undefined, subject: 'Héraðsdómur Reykjavíkur - aðgangur að málsgögnum', - text: expect.anything(), // same as hmtl but stripped hmtl tags + text: expect.anything(), // same as html but stripped html tags html: `Héraðsdómur Reykjavíkur hefur skráð þig verjanda í máli ${theCase.courtCaseNumber}.

Gögn málsins eru aðgengileg á yfirlitssíðu málsins í Réttarvörslugátt.`, }) }) }) - describe('when sending defender data is missing', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, + describe('when the case has civil claims and the advocate is a lawyer', () => { + const caseId = uuid() + const civilClaimant = { + hasSpokesperson: true, + spokespersonNationalId: '1234567890', + spokespersonEmail: 'recipient@gmail.com', + spokespersonName: 'John Doe', + spokespersonIsLawyer: true, + } + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + court, + courtCaseNumber: 'S-123/2022', + civilClaimants: [civilClaimant], + } as Case + + beforeEach(async () => { + await givenWhenThen(caseId, theCase, notificationDTO) + }) + + it('should send correct email', () => { + expect(mockEmailService.sendEmail).toHaveBeenCalledTimes(1) + expect(mockEmailService.sendEmail).toHaveBeenCalledWith({ + from: { + name: mockConfig.email.fromName, + address: mockConfig.email.fromEmail, + }, + to: [ + { + name: civilClaimant.spokespersonName, + address: civilClaimant.spokespersonEmail, + }, + ], + replyTo: { + name: mockConfig.email.replyToName, + address: mockConfig.email.replyToEmail, + }, + attachments: undefined, + subject: `Skráning í máli ${theCase.courtCaseNumber}`, + text: expect.anything(), // same as html but stripped html tags + html: `Héraðsdómur Reykjavíkur hefur skráð þig lögmann einkaréttarkröfuhafa í máli ${theCase.courtCaseNumber}.

Sjá nánar á yfirlitssíðu málsins í Réttarvörslugátt.`, + }) + }) + }) + + describe('when the case has civil claims and the advocate is a legal rights protector', () => { + const caseId = uuid() + const civilClaimant = { + hasSpokesperson: true, + spokespersonNationalId: '1234567890', + spokespersonEmail: 'recipient@gmail.com', + spokespersonName: 'John Doe', + spokespersonIsLawyer: false, + } + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + court, + courtCaseNumber: 'S-123/2022', + civilClaimants: [civilClaimant], + } as Case + + beforeEach(async () => { + await givenWhenThen(caseId, theCase, notificationDTO) + }) + + it('should send correct email', () => { + expect(mockEmailService.sendEmail).toHaveBeenCalledTimes(1) + expect(mockEmailService.sendEmail).toHaveBeenCalledWith({ + from: { + name: mockConfig.email.fromName, + address: mockConfig.email.fromEmail, + }, + to: [ + { + name: civilClaimant.spokespersonName, + address: civilClaimant.spokespersonEmail, + }, + ], + replyTo: { + name: mockConfig.email.replyToName, + address: mockConfig.email.replyToEmail, + }, + attachments: undefined, + subject: `Skráning í máli ${theCase.courtCaseNumber}`, + text: expect.anything(), // same as html but stripped html tags + html: `Héraðsdómur Reykjavíkur hefur skráð þig réttargæslumann einkaréttarkröfuhafa í máli ${theCase.courtCaseNumber}.

Sjá nánar á yfirlitssíðu málsins í Réttarvörslugátt.`, + }) + }) + }) + + describe('when the case has civil claims and civil claimant does not have representation', () => { + const caseId = uuid() + const civilClaimant = { + hasSpokesperson: false, } + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + court, + courtCaseNumber: 'S-123/2022', + civilClaimants: [civilClaimant], + } as Case + + beforeEach(async () => { + await givenWhenThen(caseId, theCase, notificationDTO) + }) + + it('should send correct email', () => { + expect(mockEmailService.sendEmail).not.toHaveBeenCalled() + }) + }) + + describe('when sending defender data is missing', () => { const caseId = uuid() const theCase = { type: CaseType.INDICTMENT, @@ -139,7 +252,7 @@ describe('InternalNotificationController - Send defender assigned notifications' beforeEach(async () => { const mockCreate = mockNotificationModel.create as jest.Mock mockCreate.mockResolvedValueOnce({} as Notification) - then = await givenWhenThen(caseId, theCase, notificationDto) + then = await givenWhenThen(caseId, theCase, notificationDTO) }) it('should not send notification', () => { @@ -150,10 +263,6 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('record notification', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() const defendant = { defenderEmail: 'recipient@gmail.com', @@ -169,14 +278,14 @@ describe('InternalNotificationController - Send defender assigned notifications' beforeEach(async () => { const mockCreate = mockNotificationModel.create as jest.Mock mockCreate.mockResolvedValueOnce({} as Notification) - await givenWhenThen(caseId, theCase, notificationDto) + await givenWhenThen(caseId, theCase, notificationDTO) }) - it('should record notfication', () => { + it('should record notification', () => { expect(mockNotificationModel.create).toHaveBeenCalledTimes(1) expect(mockNotificationModel.create).toHaveBeenCalledWith({ caseId, - type: notificationDto.type, + type: notificationDTO.type, recipients: [ { address: defendant.defenderEmail, @@ -188,10 +297,6 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('returns that the notification was sent', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() const theCase = { id: caseId, @@ -209,7 +314,7 @@ describe('InternalNotificationController - Send defender assigned notifications' beforeEach(async () => { const mockCreate = mockNotificationModel.create as jest.Mock mockCreate.mockResolvedValueOnce({} as Notification) - then = await givenWhenThen(caseId, theCase, notificationDto) + then = await givenWhenThen(caseId, theCase, notificationDTO) }) it('should return notification was sent', () => { @@ -218,10 +323,6 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('only send notification once to defender', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() const defendant = { defenderEmail: 'recipient@gmail.com', @@ -246,12 +347,12 @@ describe('InternalNotificationController - Send defender assigned notifications' notifications: [ { caseId, - type: notificationDto.type, + type: notificationDTO.type, recipients: [{ address: defendant.defenderEmail, success: true }], }, ], } as Case, - notificationDto, + notificationDTO, ) }) @@ -263,10 +364,6 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('should send email to every defender', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() const defender1 = { defenderEmail: 'some-email@island.is' } const defender2 = { defenderEmail: 'other-email@island.is' } @@ -281,7 +378,7 @@ describe('InternalNotificationController - Send defender assigned notifications' beforeEach(async () => { const mockCreate = mockNotificationModel.create as jest.Mock mockCreate.mockResolvedValueOnce({} as Notification) - then = await givenWhenThen(caseId, theCase, notificationDto) + then = await givenWhenThen(caseId, theCase, notificationDTO) }) it('should return notification was sent', () => { @@ -292,10 +389,6 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('should only send one email to each defender', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() const defender1 = { defenderNationalId: '1234567890', @@ -315,7 +408,7 @@ describe('InternalNotificationController - Send defender assigned notifications' beforeEach(async () => { const mockCreate = mockNotificationModel.create as jest.Mock mockCreate.mockResolvedValueOnce({} as Notification) - then = await givenWhenThen(caseId, theCase, notificationDto) + then = await givenWhenThen(caseId, theCase, notificationDTO) }) it('should return notification was sent', () => { @@ -338,7 +431,7 @@ describe('InternalNotificationController - Send defender assigned notifications' }, attachments: undefined, subject: 'Héraðsdómur Reykjavíkur - aðgangur að málsgögnum', - text: expect.anything(), // same as hmtl but stripped hmtl tags + text: expect.anything(), // same as html but stripped html tags html: `Héraðsdómur Reykjavíkur hefur skráð þig verjanda í máli ${theCase.courtCaseNumber}.

Gögn málsins eru aðgengileg á yfirlitssíðu málsins í Réttarvörslugátt.`, }) expect(then.result).toEqual(expect.objectContaining({ delivered: true })) @@ -346,12 +439,7 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('when sending assigned defender notifications in a restriction case', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() - const theCase = { id: caseId, type: CaseType.ADMISSION_TO_FACILITY, @@ -364,7 +452,7 @@ describe('InternalNotificationController - Send defender assigned notifications' } as Case beforeEach(async () => { - await givenWhenThen(caseId, theCase, notificationDto) + await givenWhenThen(caseId, theCase, notificationDTO) }) it('should send email with link', () => { @@ -393,12 +481,7 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('when sending assigned defender without national id notifications in a restriction case', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() - const theCase = { id: caseId, type: CaseType.ADMISSION_TO_FACILITY, @@ -410,7 +493,7 @@ describe('InternalNotificationController - Send defender assigned notifications' } as Case beforeEach(async () => { - await givenWhenThen(caseId, theCase, notificationDto) + await givenWhenThen(caseId, theCase, notificationDTO) }) it('should send an email without a link', () => { @@ -439,12 +522,7 @@ describe('InternalNotificationController - Send defender assigned notifications' }) describe('when sending notifications in an investigation case', () => { - const notificationDto: CaseNotificationDto = { - user: { id: userId } as User, - type: NotificationType.DEFENDER_ASSIGNED, - } const caseId = uuid() - const theCase = { id: caseId, type: CaseType.PHONE_TAPPING, @@ -456,7 +534,7 @@ describe('InternalNotificationController - Send defender assigned notifications' } as Case beforeEach(async () => { - await givenWhenThen(caseId, theCase, notificationDto) + await givenWhenThen(caseId, theCase, notificationDTO) }) it('should not send email', () => { diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendDefenderAssignedNotifications.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendAdvocateAssignedNotifications.spec.ts similarity index 91% rename from apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendDefenderAssignedNotifications.spec.ts rename to apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendAdvocateAssignedNotifications.spec.ts index 9343649fb891..acc19f13a96f 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendDefenderAssignedNotifications.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendAdvocateAssignedNotifications.spec.ts @@ -17,7 +17,7 @@ interface Then { type GivenWhenThen = (caseId: string) => Promise -describe('NotificationController - Send defender assigned notification', () => { +describe('NotificationController - Send advocate assigned notification', () => { const userId = uuid() const user = { id: userId } as User @@ -39,7 +39,7 @@ describe('NotificationController - Send defender assigned notification', () => { await notificationController .sendCaseNotification(caseId, user, { id: caseId } as Case, { - type: NotificationType.DEFENDER_ASSIGNED, + type: NotificationType.ADVOCATE_ASSIGNED, }) .then((result) => (then.result = result)) .catch((error) => (then.error = error)) @@ -61,7 +61,7 @@ describe('NotificationController - Send defender assigned notification', () => { type: MessageType.NOTIFICATION, user, caseId, - body: { type: NotificationType.DEFENDER_ASSIGNED }, + body: { type: NotificationType.ADVOCATE_ASSIGNED }, }, ]) expect(then.result).toEqual({ notificationSent: true }) diff --git a/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCourtDateNotification.spec.ts b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCourtDateNotification.spec.ts index 4d99bbd951ac..180b8de0934e 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCourtDateNotification.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/test/notificationController/sendCourtDateNotification.spec.ts @@ -82,7 +82,7 @@ describe('NotificationController - Send court date notification', () => { type: MessageType.NOTIFICATION, user, caseId, - body: { type: NotificationType.DEFENDER_ASSIGNED }, + body: { type: NotificationType.ADVOCATE_ASSIGNED }, }, ]) expect(then.result).toEqual({ notificationSent: true }) diff --git a/apps/judicial-system/web/src/components/Inputs/InputAdvocate.tsx b/apps/judicial-system/web/src/components/Inputs/InputAdvocate.tsx index e5bfaec3c2fe..75206b7d7e37 100644 --- a/apps/judicial-system/web/src/components/Inputs/InputAdvocate.tsx +++ b/apps/judicial-system/web/src/components/Inputs/InputAdvocate.tsx @@ -12,7 +12,7 @@ import { useIntl } from 'react-intl' import { SingleValue } from 'react-select' import { Box, Input, Select } from '@island.is/island-ui/core' -import { type Lawyer } from '@island.is/judicial-system/types' +import { AdvocateType, type Lawyer } from '@island.is/judicial-system/types' import { FormContext } from '@island.is/judicial-system-web/src/components' import { ReactSelectOption, @@ -39,7 +39,7 @@ interface Props { onAdvocateNotFound?: (advocateNotFound: boolean) => void disabled?: boolean | null clientId?: string | null - advocateType?: 'defender' | 'spokesperson' | 'legal_rights_protector' + advocateType?: AdvocateType isCivilClaim?: boolean } @@ -319,7 +319,7 @@ const InputAdvocate: FC = ({ icon="search" options={options} label={ - advocateType === 'legal_rights_protector' + advocateType === AdvocateType.LEGAL_RIGHTS_PROTECTOR ? formatMessage(strings.spokespersonNameLabel) : formatMessage(strings.nameLabel, { sessionArrangements: workingCase.sessionArrangements, @@ -367,7 +367,7 @@ const InputAdvocate: FC = ({ name="defenderEmail" autoComplete="off" label={ - advocateType === 'legal_rights_protector' + advocateType === AdvocateType.LEGAL_RIGHTS_PROTECTOR ? formatMessage(strings.spokespersonEmailLabel) : formatMessage(strings.emailLabel, { sessionArrangements: workingCase.sessionArrangements, @@ -481,7 +481,7 @@ const InputAdvocate: FC = ({ name="defenderPhoneNumber" autoComplete="off" label={ - advocateType === 'legal_rights_protector' + advocateType === AdvocateType.LEGAL_RIGHTS_PROTECTOR ? formatMessage(strings.spokespersonPhoneNumberLabel) : formatMessage(strings.phoneNumberLabel, { sessionArrangements: workingCase.sessionArrangements, diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/Advocates.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/Advocates.tsx index ffdba0747338..09e131c55de5 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/Advocates.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/Advocates.tsx @@ -33,7 +33,7 @@ const Advocates = () => { const handleNavigationTo = useCallback( async (destination: string) => { - await sendNotification(workingCase.id, NotificationType.DEFENDER_ASSIGNED) + await sendNotification(workingCase.id, NotificationType.ADVOCATE_ASSIGNED) router.push(`${destination}/${workingCase.id}`) }, [workingCase.id, sendNotification, router], diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/SelectCivilClaimantAdvocate.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/SelectCivilClaimantAdvocate.tsx index c79fb2078f01..7047b7724dfd 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/SelectCivilClaimantAdvocate.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Advocates/SelectCivilClaimantAdvocate.tsx @@ -9,6 +9,7 @@ import { RadioButton, Text, } from '@island.is/island-ui/core' +import { AdvocateType } from '@island.is/judicial-system/types' import { BlueBox, FormContext, @@ -87,8 +88,8 @@ const SelectCivilClaimantAdvocate: FC = ({ civilClaimant }) => { clientId={civilClaimant.id} advocateType={ civilClaimant.spokespersonIsLawyer - ? 'defender' - : 'legal_rights_protector' + ? AdvocateType.LAWYER + : AdvocateType.LEGAL_RIGHTS_PROTECTOR } disabled={ civilClaimant.spokespersonIsLawyer === null || diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx index c76de5e43862..3a1800e8c7a2 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx @@ -10,7 +10,10 @@ import { Text, } from '@island.is/island-ui/core' import * as constants from '@island.is/judicial-system/consts' -import { isTrafficViolationCase } from '@island.is/judicial-system/types' +import { + AdvocateType, + isTrafficViolationCase, +} from '@island.is/judicial-system/types' import { core, titles } from '@island.is/judicial-system-web/messages' import { BlueBox, @@ -596,8 +599,8 @@ const Processing: FC = () => { clientId={civilClaimant.id} advocateType={ civilClaimant.spokespersonIsLawyer - ? 'defender' - : 'legal_rights_protector' + ? AdvocateType.LAWYER + : AdvocateType.LEGAL_RIGHTS_PROTECTOR } disabled={ civilClaimant.spokespersonIsLawyer === null || diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 29817dad0bf6..502e7ce2f93f 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -98,7 +98,7 @@ export { offenseSubstances, } from './lib/indictmentCount' -export { type Lawyer, mapToLawyer } from './lib/defender' +export { type Lawyer, mapToLawyer, AdvocateType } from './lib/advocate' export type { SubstanceMap } from './lib/indictmentCount' diff --git a/libs/judicial-system/types/src/lib/defender.ts b/libs/judicial-system/types/src/lib/advocate.ts similarity index 89% rename from libs/judicial-system/types/src/lib/defender.ts rename to libs/judicial-system/types/src/lib/advocate.ts index d4ae0aee081b..3b298721edbb 100644 --- a/libs/judicial-system/types/src/lib/defender.ts +++ b/libs/judicial-system/types/src/lib/advocate.ts @@ -42,6 +42,12 @@ type LawyerFull = { InternationConnection: string } +export enum AdvocateType { + DEFENDER = 'DEFENDER', + LAWYER = 'LAWYER', + LEGAL_RIGHTS_PROTECTOR = 'LEGAL_RIGHTS_PROTECTOR', +} + export const mapToLawyer = (lawyer: LawyerFull): Lawyer => { return { name: lawyer.Name, diff --git a/libs/judicial-system/types/src/lib/notification.ts b/libs/judicial-system/types/src/lib/notification.ts index afdf6ec82930..26d38136f834 100644 --- a/libs/judicial-system/types/src/lib/notification.ts +++ b/libs/judicial-system/types/src/lib/notification.ts @@ -6,7 +6,7 @@ export enum NotificationType { RULING = 'RULING', MODIFIED = 'MODIFIED', REVOKED = 'REVOKED', - DEFENDER_ASSIGNED = 'DEFENDER_ASSIGNED', + ADVOCATE_ASSIGNED = 'ADVOCATE_ASSIGNED', DEFENDANTS_NOT_UPDATED_AT_COURT = 'DEFENDANTS_NOT_UPDATED_AT_COURT', APPEAL_TO_COURT_OF_APPEALS = 'APPEAL_TO_COURT_OF_APPEALS', APPEAL_RECEIVED_BY_COURT = 'APPEAL_RECEIVED_BY_COURT',