Skip to content

Commit

Permalink
feat(j-s): Notifications to prosecutors office in completed indictmen…
Browse files Browse the repository at this point in the history
…ts (#17174)

* fix(j-s): Display confirmation modal before completing case

* feat(j-s): Notifications for prosecutor

* chore: charts update dirty files

* chore: nx format:write update dirty files

* fix(j-s): Only send verdict info if there was a ruling

* Update eventLog.service.ts

---------

Co-authored-by: andes-it <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 10, 2024
1 parent b3e0878 commit 22c5b52
Show file tree
Hide file tree
Showing 25 changed files with 630 additions and 37 deletions.
2 changes: 2 additions & 0 deletions apps/judicial-system/backend/infra/judicial-system-backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export const serviceSetup = (): ServiceBuilder<'judicial-system-backend'> =>
EMAIL_FROM_NAME: '/k8s/judicial-system/EMAIL_FROM_NAME',
EMAIL_REPLY_TO: '/k8s/judicial-system/EMAIL_REPLY_TO',
EMAIL_REPLY_TO_NAME: '/k8s/judicial-system/EMAIL_REPLY_TO_NAME',
POLICE_INSTITUTIONS_EMAILS:
'/k8s/judicial-system/POLICE_INSTITUTIONS_EMAILS',
PRISON_EMAIL: '/k8s/judicial-system/PRISON_EMAIL',
PRISON_ADMIN_EMAIL: '/k8s/judicial-system/PRISON_ADMIN_EMAIL',
PRISON_ADMIN_INDICTMENT_EMAILS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const notifications = {
}),
emailWhitelistDomains: defineMessage({
id: 'judicial.system.backend:notifications.email_whitelist_domains',
defaultMessage: 'omnitrix.is,kolibri.is',
defaultMessage: 'omnitrix.is,kolibri.is,dummy.dd',
description: 'Notað til að tilgreina hvort póstfang sé í hvítlista',
}),
readyForCourt: defineMessages({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Module } from '@nestjs/common'
import { forwardRef, Module } from '@nestjs/common'
import { SequelizeModule } from '@nestjs/sequelize'

import { MessageModule } from '@island.is/judicial-system/message'

import { EventLog } from './models/eventLog.model'
import { EventLogController } from './eventLog.controller'
import { EventLogService } from './eventLog.service'

@Module({
imports: [SequelizeModule.forFeature([EventLog])],
imports: [
forwardRef(() => MessageModule),
SequelizeModule.forFeature([EventLog]),
],
providers: [EventLogService],
exports: [EventLogService],
controllers: [EventLogController],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { InjectModel } from '@nestjs/sequelize'
import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'

import { EventType } from '@island.is/judicial-system/types'
import { MessageService, MessageType } from '@island.is/judicial-system/message'
import {
EventNotificationType,
EventType,
} from '@island.is/judicial-system/types'

import { CreateEventLogDto } from './dto/createEventLog.dto'
import { EventLog } from './models/eventLog.model'
Expand All @@ -20,11 +24,19 @@ const allowMultiple: EventType[] = [
EventType.INDICTMENT_CONFIRMED,
]

const eventToNotificationMap: Partial<
Record<EventType, EventNotificationType>
> = {
INDICTMENT_SENT_TO_PUBLIC_PROSECUTOR:
EventNotificationType.INDICTMENT_SENT_TO_PUBLIC_PROSECUTOR,
}

@Injectable()
export class EventLogService {
constructor(
@InjectModel(EventLog)
private readonly eventLogModel: typeof EventLog,
private readonly messageService: MessageService,
@Inject(LOGGER_PROVIDER)
private readonly logger: Logger,
) {}
Expand Down Expand Up @@ -58,6 +70,10 @@ export class EventLogService {
// Tolerate failure but log error
this.logger.error('Failed to create event log', error)
}

if (caseId) {
this.addEventNotificationToQueue(eventType, caseId)
}
}

async loginMap(
Expand Down Expand Up @@ -86,4 +102,23 @@ export class EventLogService {
),
)
}

// Sends events to queue for notification dispatch
private addEventNotificationToQueue(eventType: EventType, caseId: string) {
const notificationType = eventToNotificationMap[eventType]

if (notificationType) {
try {
this.messageService.sendMessagesToQueue([
{
type: MessageType.EVENT_NOTIFICATION_DISPATCH,
caseId: caseId,
body: { type: notificationType },
},
])
} catch (error) {
this.logger.error('Failed to send event notification to queue', error)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IsEnum, IsNotEmpty } from 'class-validator'

import { ApiProperty } from '@nestjs/swagger'

import { IndictmentCaseNotificationType } from '@island.is/judicial-system/types'

export class IndictmentCaseNotificationDto {
@IsNotEmpty()
@IsEnum(IndictmentCaseNotificationType)
@ApiProperty({ enum: IndictmentCaseNotificationType })
readonly type!: IndictmentCaseNotificationType
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@ import { IsEnum, IsNotEmpty } from 'class-validator'

import { ApiProperty } from '@nestjs/swagger'

import { NotificationDispatchType } from '@island.is/judicial-system/types'
import {
EventNotificationType,
NotificationDispatchType,
} from '@island.is/judicial-system/types'

export class NotificationDispatchDto {
@IsNotEmpty()
@IsEnum(NotificationDispatchType)
@ApiProperty({ enum: NotificationDispatchType })
readonly type!: NotificationDispatchType
}

export class EventNotificationDispatchDto {
@IsNotEmpty()
@IsEnum(EventNotificationType)
@ApiProperty({ enum: EventNotificationType })
readonly type!: EventNotificationType
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import {
messageEndpoint,
MessageType,
} from '@island.is/judicial-system/message'
import { indictmentCases } from '@island.is/judicial-system/types'

import { Case, CaseHasExistedGuard, CurrentCase } from '../case'
import { Case, CaseHasExistedGuard, CaseTypeGuard, CurrentCase } from '../case'
import {
CivilClaimant,
CivilClaimantExistsGuard,
Expand All @@ -30,13 +31,18 @@ import { SubpoenaExistsGuard } from '../subpoena'
import { CaseNotificationDto } from './dto/caseNotification.dto'
import { CivilClaimantNotificationDto } from './dto/civilClaimantNotification.dto'
import { DefendantNotificationDto } from './dto/defendantNotification.dto'
import { IndictmentCaseNotificationDto } from './dto/indictmentCaseNotification.dto'
import { InstitutionNotificationDto } from './dto/institutionNotification.dto'
import { NotificationDispatchDto } from './dto/notificationDispatch.dto'
import {
EventNotificationDispatchDto,
NotificationDispatchDto,
} from './dto/notificationDispatch.dto'
import { SubpoenaNotificationDto } from './dto/subpoenaNotification.dto'
import { DeliverResponse } from './models/deliver.response'
import { CaseNotificationService } from './services/caseNotification/caseNotification.service'
import { CivilClaimantNotificationService } from './services/civilClaimantNotification/civilClaimantNotification.service'
import { DefendantNotificationService } from './services/defendantNotification/defendantNotification.service'
import { IndictmentCaseNotificationService } from './services/indictmentCaseNotification/indictmentCaseNotification.service'
import { InstitutionNotificationService } from './services/institutionNotification/institutionNotification.service'
import { SubpoenaNotificationService } from './services/subpoenaNotification/subpoenaNotification.service'
import { NotificationDispatchService } from './notificationDispatch.service'
Expand All @@ -52,6 +58,7 @@ export class InternalNotificationController {
private readonly subpoenaNotificationService: SubpoenaNotificationService,
private readonly defendantNotificationService: DefendantNotificationService,
private readonly civilClaimantNotificationService: CivilClaimantNotificationService,
private readonly indictmentCaseNotificationService: IndictmentCaseNotificationService,
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

Expand All @@ -77,6 +84,29 @@ export class InternalNotificationController {
)
}

@Post(
`case/:caseId/${messageEndpoint[MessageType.INDICTMENT_CASE_NOTIFICATION]}`,
)
@UseGuards(CaseHasExistedGuard, new CaseTypeGuard(indictmentCases))
@ApiCreatedResponse({
type: DeliverResponse,
description: 'Sends a case notification for an existing indictment case',
})
sendIndictmentCaseNotification(
@Param('caseId') caseId: string,
@CurrentCase() theCase: Case,
@Body() notificationDto: IndictmentCaseNotificationDto,
): Promise<DeliverResponse> {
this.logger.debug(
`Sending ${notificationDto.type} indictment case notification for case ${caseId}`,
)

return this.indictmentCaseNotificationService.sendIndictmentCaseNotification(
notificationDto.type,
theCase,
)
}

@Post(
`case/:caseId/${
messageEndpoint[MessageType.SUBPOENA_NOTIFICATION]
Expand Down Expand Up @@ -161,34 +191,58 @@ export class InternalNotificationController {
)
}

@Post(messageEndpoint[MessageType.NOTIFICATION_DISPATCH])
@Post(messageEndpoint[MessageType.INSTITUTION_NOTIFICATION])
@ApiCreatedResponse({
type: DeliverResponse,
description: 'Dispatches notifications',
description: 'Sends an institution notification',
})
dispatchNotification(
@Body() notificationDto: NotificationDispatchDto,
sendInstitutionNotification(
@Body() notificationDto: InstitutionNotificationDto,
): Promise<DeliverResponse> {
this.logger.debug(`Dispatching ${notificationDto.type} notification`)
this.logger.debug(`Sending ${notificationDto.type} notification`)

return this.notificationDispatchService.dispatchNotification(
return this.institutionNotificationService.sendNotification(
notificationDto.type,
notificationDto.prosecutorsOfficeId,
)
}

@Post(messageEndpoint[MessageType.INSTITUTION_NOTIFICATION])
@Post(
`case/:caseId/${messageEndpoint[MessageType.EVENT_NOTIFICATION_DISPATCH]}`,
)
@UseGuards(CaseHasExistedGuard)
@ApiCreatedResponse({
type: DeliverResponse,
description: 'Sends an institution notification',
description:
'Dispatches notifications in response to events logged in event log',
})
sendNotification(
@Body() notificationDto: InstitutionNotificationDto,
dispatchEventNotification(
@Param('caseId') caseId: string,
@CurrentCase() theCase: Case,
@Body() notificationDto: EventNotificationDispatchDto,
): Promise<DeliverResponse> {
this.logger.debug(`Sending ${notificationDto.type} notification`)
this.logger.debug(
`Dispatching ${notificationDto.type} event notification for case ${caseId}`,
)

return this.institutionNotificationService.sendNotification(
return this.notificationDispatchService.dispatchEventNotification(
notificationDto.type,
theCase,
)
}

@Post(messageEndpoint[MessageType.NOTIFICATION_DISPATCH])
@ApiCreatedResponse({
type: DeliverResponse,
description: 'Dispatches notifications',
})
dispatchNotification(
@Body() notificationDto: NotificationDispatchDto,
): Promise<DeliverResponse> {
this.logger.debug(`Dispatching ${notificationDto.type} notification`)

return this.notificationDispatchService.dispatchNotification(
notificationDto.type,
notificationDto.prosecutorsOfficeId,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export const notificationModuleConfig = defineConfig({
courtsEmails: env.requiredJSON('COURTS_EMAILS', {}) as {
[key: string]: string
},
policeInstitutionEmails: env.requiredJSON(
'POLICE_INSTITUTIONS_EMAILS',
{},
) as {
[key: string]: string
},
},
sms: {
courtsMobileNumbers: env.requiredJSON('COURTS_MOBILE_NUMBERS', {}) as {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Notification } from './models/notification.model'
import { CaseNotificationService } from './services/caseNotification/caseNotification.service'
import { CivilClaimantNotificationService } from './services/civilClaimantNotification/civilClaimantNotification.service'
import { DefendantNotificationService } from './services/defendantNotification/defendantNotification.service'
import { IndictmentCaseNotificationService } from './services/indictmentCaseNotification/indictmentCaseNotification.service'
import { InstitutionNotificationService } from './services/institutionNotification/institutionNotification.service'
import { SubpoenaNotificationService } from './services/subpoenaNotification/subpoenaNotification.service'
import { InternalNotificationController } from './internalNotification.controller'
Expand Down Expand Up @@ -47,6 +48,7 @@ import { NotificationDispatchService } from './notificationDispatch.service'
CaseNotificationService,
CivilClaimantNotificationService,
DefendantNotificationService,
IndictmentCaseNotificationService,
InstitutionNotificationService,
NotificationService,
NotificationDispatchService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ 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 {
EventNotificationType,
IndictmentCaseNotificationType,
InstitutionNotificationType,
InstitutionType,
NotificationDispatchType,
} from '@island.is/judicial-system/types'

import { Case } from '../case'
import { Institution, InstitutionService } from '../institution'
import { DeliverResponse } from './models/deliver.response'

Expand Down Expand Up @@ -63,4 +67,43 @@ export class NotificationDispatchService {

return { delivered: true }
}

private async dispatchIndictmentSentToPublicProsecutorNotifications(
theCase: Case,
): Promise<void> {
return this.messageService.sendMessagesToQueue([
{
type: MessageType.INDICTMENT_CASE_NOTIFICATION,
caseId: theCase.id,
body: {
type: IndictmentCaseNotificationType.INDICTMENT_VERDICT_INFO,
},
},
])
}

async dispatchEventNotification(
type: EventNotificationType,
theCase: Case,
): Promise<DeliverResponse> {
try {
switch (type) {
case EventNotificationType.INDICTMENT_SENT_TO_PUBLIC_PROSECUTOR:
await this.dispatchIndictmentSentToPublicProsecutorNotifications(
theCase,
)
break
default:
throw new InternalServerErrorException(
`Invalid notification type ${type}`,
)
}
} catch (error) {
this.logger.error('Failed to dispatch event notification', error)

return { delivered: false }
}

return { delivered: true }
}
}
Loading

0 comments on commit 22c5b52

Please sign in to comment.