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

chore(j-s): Notifications to advocates in civil claims cases #16264

Merged
merged 40 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e935493
fix(j-s): Civil claimant view for courts
unakb Sep 25, 2024
8e17b19
feat(j-s): Judge can add and remove advocates
unakb Sep 26, 2024
f4d8eaa
Merge branch 'main' into j-s/civil-claimant-courts
unakb Sep 26, 2024
1a358c8
Update civilClaimant.controller.ts
unakb Sep 26, 2024
5ccdc51
Merge branch 'j-s/civil-claimant-courts' of https://github.com/island…
unakb Sep 26, 2024
a4d7153
Fixed key on Box
unakb Oct 3, 2024
5b9bdea
Change DEFENDER_ASSIGNED to ADVOCATE_ASSIGNED
oddsson Oct 3, 2024
fcf3956
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 3, 2024
23756d2
Merge branch 'j-s/civil-claimant-courts' of github.com:island-is/isla…
oddsson Oct 3, 2024
1f603d4
Checkpoint
oddsson Oct 3, 2024
ddbe140
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 4, 2024
612e230
Checkpoint
oddsson Oct 4, 2024
d264166
Update string
oddsson Oct 4, 2024
8263ce1
Add tests
oddsson Oct 4, 2024
d0e3d38
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 7, 2024
eb4d0c6
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 7, 2024
3f77cd7
Merge branch 'j-s/advocate-notifications' of github.com:island-is/isl…
oddsson Oct 7, 2024
b41d4c6
Rename defender -- advocate
oddsson Oct 7, 2024
18355bb
Rename defender -- advocate
oddsson Oct 7, 2024
2b8d4e5
Fix typo: hmtl -- html
oddsson Oct 7, 2024
1c2fdd7
Refactor tests
oddsson Oct 7, 2024
0ec93dd
Add promise handling to email sending
oddsson Oct 7, 2024
276040d
Rename parameters
oddsson Oct 7, 2024
95f00cd
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 8, 2024
5c54105
Fix tests
oddsson Oct 8, 2024
5925a58
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 9, 2024
b41853e
Reorder imports
oddsson Oct 9, 2024
38ca6b8
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 9, 2024
c1133f8
Fix texts
oddsson Oct 9, 2024
08b70a2
Fix texts
oddsson Oct 9, 2024
5fa9870
Fix texts
oddsson Oct 10, 2024
f8c2dee
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 10, 2024
88ee549
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 11, 2024
5f4d796
Merge branch 'j-s/advocate-notifications' of github.com:island-is/isl…
oddsson Oct 11, 2024
9f2f435
Fix tests
oddsson Oct 11, 2024
e506afc
Merge branch 'main' of github.com:island-is/island.is into j-s/advoca…
oddsson Oct 11, 2024
eac05f6
Merge branch 'j-s/advocate-notifications' of github.com:island-is/isl…
oddsson Oct 11, 2024
aa96f55
Use correct types
oddsson Oct 11, 2024
a3439ff
Use correct types
oddsson Oct 11, 2024
740a16d
Merge branch 'main' into j-s/advocate-notifications
kodiakhq[bot] Oct 11, 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
@@ -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',
})
},
}
54 changes: 40 additions & 14 deletions apps/judicial-system/backend/src/app/formatters/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
})
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: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
},
)
: formatMessage(notifications.advocateAssignedEmail.bodyAccess, {
defenderHasAccessToRVG: Boolean(overviewUrl),
court: theCase.court?.name,
advocateType,
courtCaseNumber: capitalize(theCase.courtCaseNumber ?? ''),
linkStart: `<a href="${overviewUrl}">`,
linkEnd: '</a>',
})

return { body, subject }
}
Expand Down
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 @@ -21,7 +21,7 @@ export {
formatProsecutorReceivedByCourtSmsNotification,
formatDefenderCourtDateLinkEmailNotification,
formatDefenderResubmittedToCourtEmailNotification,
formatDefenderAssignedEmailNotification,
formatAdvocateAssignedEmailNotification,
formatCourtIndictmentReadyForCourtEmailNotification,
formatDefenderRoute,
formatDefenderReadyForCourtEmailNotification,
Expand Down
22 changes: 17 additions & 5 deletions apps/judicial-system/backend/src/app/messages/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}.<br /><br />{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}.<br /><br />{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: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const districtCourtJudgeNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
oddsson marked this conversation as resolved.
Show resolved Hide resolved
],
}

Expand All @@ -39,7 +39,7 @@ export const districtCourtRegistrarNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
}

Expand All @@ -50,7 +50,7 @@ export const districtCourtAssistantNotificationRule: RolesRule = {
dtoField: 'type',
dtoFieldValues: [
NotificationType.COURT_DATE,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
],
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
lowercase,
} from '@island.is/judicial-system/formatters'
import {
AdvocateType,
CaseAppealRulingDecision,
CaseCustodyRestrictions,
CaseDecision,
Expand All @@ -50,13 +51,13 @@ import {
} from '@island.is/judicial-system/types'

import {
formatAdvocateAssignedEmailNotification,
formatCourtHeadsUpSmsNotification,
formatCourtIndictmentReadyForCourtEmailNotification,
formatCourtOfAppealJudgeAssignedEmailNotification,
formatCourtReadyForCourtSmsNotification,
formatCourtResubmittedToCourtSmsNotification,
formatCourtRevokedSmsNotification,
formatDefenderAssignedEmailNotification,
formatDefenderCourtDateEmailNotification,
formatDefenderCourtDateLinkEmailNotification,
formatDefenderReadyForCourtEmailNotification,
Expand Down Expand Up @@ -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,
)

Expand All @@ -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,
Expand All @@ -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<Recipient> {
const { subject, body } = formatDefenderAssignedEmailNotification(
const { subject, body } = formatAdvocateAssignedEmailNotification(
this.formatMessage,
theCase,
defenderNationalId &&
advocateType,
oddsson marked this conversation as resolved.
Show resolved Hide resolved
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<DeliverResponse> {
const promises: Promise<Recipient>[] = []
Expand All @@ -1597,27 +1600,61 @@ 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,
),
)
}
}

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,
)
Expand All @@ -1636,7 +1673,7 @@ export class InternalNotificationService extends BaseNotificationService {

return this.recordNotification(
theCase.id,
NotificationType.DEFENDER_ASSIGNED,
NotificationType.ADVOCATE_ASSIGNED,
recipients,
)
}
Expand Down Expand Up @@ -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:
Expand Down
Loading