Skip to content

Commit

Permalink
chore(j-s): Civil claimant spokesperson assigned notifications (#16750)
Browse files Browse the repository at this point in the history
* feat(j-s): Handle advocate assigned to defendant notification

* Update defendant.service.ts

* feat(j-s): Send civil claimant notification when assigned

* Update defendantNotification.service.ts

* fix(j-s): Small fix on modal texts

* fix(j-s): Stop using advocate for defender emails

* fix(j-s): remove advocate assigned from user roles rules

* fix(j-s): remove and change tests

* fix(j-s):  Tests

* test(j-s): Defendant notification tests

* Update update.spec.ts

* Update update.spec.ts

* Update sendDefenderAssignedNotifications.spec.ts

* Update defendantNotification.service.ts

* test(j-s): Add tests

* fix(j-s): Tests

* test(j-s): Added more civil claimant tests

* test(j-s): Added more civil claimant tests

* Update civilClaimantNotification.service.ts

* Update internalNotification.controller.ts

* Update notification.module.ts

* Update sendAdvocateAssignedNotifications.spec.ts

* Update civilClaimant.service.ts

* Update civilClaimant.service.ts

* test(j-s): Civil claimant exists guard tests

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Guðjón Guðjónsson <gudjon@kolibri.is>
  • Loading branch information
3 people authored and jonnigs committed Nov 26, 2024
1 parent 17b6df6 commit 51eb975
Show file tree
Hide file tree
Showing 30 changed files with 1,124 additions and 263 deletions.
43 changes: 0 additions & 43 deletions apps/judicial-system/backend/src/app/formatters/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,49 +668,6 @@ export const formatCustodyRestrictions = (
})
}

export const formatAdvocateAssignedEmailNotification = (
formatMessage: FormatMessage,
theCase: Case,
advocateType: AdvocateType,
overviewUrl?: string,
): SubjectAndBody => {
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 }
}

export const formatCourtOfAppealJudgeAssignedEmailNotification = (
formatMessage: FormatMessage,
caseNumber: string,
Expand Down
1 change: 0 additions & 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,6 @@ export {
formatProsecutorReceivedByCourtSmsNotification,
formatDefenderCourtDateLinkEmailNotification,
formatDefenderResubmittedToCourtEmailNotification,
formatAdvocateAssignedEmailNotification,
formatCourtIndictmentReadyForCourtEmailNotification,
formatDefenderRoute,
formatDefenderReadyForCourtEmailNotification,
Expand Down
26 changes: 0 additions & 26 deletions apps/judicial-system/backend/src/app/messages/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -607,32 +607,6 @@ 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.',
},
}),
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.',
},
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: {
id: 'judicial.system.backend:notifications.defendants_not_updated_at_court.subject',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'

import { normalizeAndFormatNationalId } from '@island.is/judicial-system/formatters'
import { CaseState } from '@island.is/judicial-system/types'
import { MessageService, MessageType } from '@island.is/judicial-system/message'
import {
CaseState,
CivilClaimantNotificationType,
} from '@island.is/judicial-system/types'

import { Case } from '../case/models/case.model'
import { UpdateCivilClaimantDto } from './dto/updateCivilClaimant.dto'
Expand All @@ -18,6 +22,7 @@ export class CivilClaimantService {
constructor(
@InjectModel(CivilClaimant)
private readonly civilClaimantModel: typeof CivilClaimant,
private readonly messageService: MessageService,
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

Expand All @@ -27,6 +32,24 @@ export class CivilClaimantService {
})
}

private async sendUpdateCivilClaimantMessages(
update: UpdateCivilClaimantDto,
updatedCivilClaimant: CivilClaimant,
): Promise<void> {
if (update.isSpokespersonConfirmed === true) {
return this.messageService.sendMessagesToQueue([
{
type: MessageType.CIVIL_CLAIMANT_NOTIFICATION,
caseId: updatedCivilClaimant.caseId,
body: {
type: CivilClaimantNotificationType.SPOKESPERSON_ASSIGNED,
},
elementId: updatedCivilClaimant.id,
},
])
}
}

async update(
caseId: string,
civilClaimantId: string,
Expand All @@ -49,6 +72,8 @@ export class CivilClaimantService {
throw new Error(`Could not update civil claimant ${civilClaimantId}`)
}

await this.sendUpdateCivilClaimantMessages(update, civilClaimants[0])

return civilClaimants[0]
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createParamDecorator } from '@nestjs/common'

import { CivilClaimant } from '../models/civilClaimant.model'

export const CurrentCivilClaimant = createParamDecorator(
(data, { args: [_1, { req }] }): CivilClaimant => req.civilClaimant,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
BadRequestException,
CanActivate,
ExecutionContext,
Injectable,
NotFoundException,
} from '@nestjs/common'

import { Case } from '../../case'

@Injectable()
export class CivilClaimantExistsGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest()

const theCase: Case = request.case

if (!theCase) {
throw new BadRequestException('Missing case')
}

const civilClaimantId = request.params.civilClaimantId

if (!civilClaimantId) {
throw new BadRequestException('Missing civil claimant id')
}

const civilClaimant = theCase.civilClaimants?.find(
(civilClaimants) => civilClaimants.id === civilClaimantId,
)

if (!civilClaimant) {
throw new NotFoundException(
`Civil claimant ${civilClaimantId} of case ${theCase.id} does not exist`,
)
}

request.civilClaimant = civilClaimant

return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { uuid } from 'uuidv4'

import {
BadRequestException,
ExecutionContext,
NotFoundException,
} from '@nestjs/common'

import { CivilClaimantExistsGuard } from '../civilClaimantExists.guard'

interface Then {
result: boolean
error: Error
}

type GivenWhenThen = () => Promise<Then>

describe('Civil Claimant Exists Guard', () => {
const mockRequest = jest.fn()
let givenWhenThen: GivenWhenThen

beforeEach(async () => {
givenWhenThen = async (): Promise<Then> => {
const guard = new CivilClaimantExistsGuard()
const then = {} as Then

try {
then.result = guard.canActivate({
switchToHttp: () => ({ getRequest: mockRequest }),
} as unknown as ExecutionContext)
} catch (error) {
then.error = error as Error
}

return then
}
})

describe('civil claimant exists', () => {
const caseId = uuid()
const civilClaimantId = uuid()
const civilClaimant = { id: civilClaimantId, caseId }
const theCase = { id: caseId, civilClaimants: [civilClaimant] }
const request = {
params: { caseId, civilClaimantId },
case: theCase,
civilClaimant: undefined,
}
let then: Then

beforeEach(async () => {
mockRequest.mockReturnValueOnce(request)

then = await givenWhenThen()
})

it('should activate', () => {
expect(then.result).toBe(true)
expect(request.civilClaimant).toBe(civilClaimant)
})
})

describe('civil claimant does not exist', () => {
const caseId = uuid()
const civilClaimantId = uuid()
const theCase = { id: caseId, civilClaimants: [] }
let then: Then

beforeEach(async () => {
mockRequest.mockReturnValueOnce({
params: { caseId, civilClaimantId },
case: theCase,
})

then = await givenWhenThen()
})

it('should throw NotFoundException', () => {
expect(then.error).toBeInstanceOf(NotFoundException)
expect(then.error.message).toBe(
`Civil claimant ${civilClaimantId} of case ${caseId} does not exist`,
)
})
})

describe('missing case', () => {
let then: Then

beforeEach(async () => {
mockRequest.mockReturnValueOnce({ params: {} })

then = await givenWhenThen()
})

it('should throw BadRequestException', () => {
expect(then.error).toBeInstanceOf(BadRequestException)
expect(then.error.message).toBe('Missing case')
})
})

describe('missing civil claimant id', () => {
const caseId = uuid()
const theCase = { id: caseId, civilClaimants: [] }
let then: Then

beforeEach(async () => {
mockRequest.mockReturnValueOnce({ params: { caseId }, case: theCase })

then = await givenWhenThen()
})

it('should throw BadRequestException', () => {
expect(then.error).toBeInstanceOf(BadRequestException)
expect(then.error.message).toBe('Missing civil claimant id')
})
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export { Defendant } from './models/defendant.model'
export { DefendantService } from './defendant.service'
export { CivilClaimant } from './models/civilClaimant.model'
export { DefendantExistsGuard } from './guards/defendantExists.guard'
export { CurrentDefendant } from './guards/defendant.decorator'

export { CivilClaimant } from './models/civilClaimant.model'
export { CivilClaimantService } from './civilClaimant.service'
export { CivilClaimantExistsGuard } from './guards/civilClaimantExists.guard'
export { CurrentCivilClaimant } from './guards/civilClaimaint.decorator'
Loading

0 comments on commit 51eb975

Please sign in to comment.