Skip to content

Commit

Permalink
chore(j-s): add slack lock for daily court hearing arrangements (#17468)
Browse files Browse the repository at this point in the history
* fix(j-s): refactor scheduler and seperate tasks in priv functions

* feat(j-s): Fetch cases on arraignment date

* chore(j-s): configure slack message

* fix(j-s): refactoring + only showing timestamp in summary

* fix(j-s): cleanup and minor refactor

* fix(j-s): cleanup and minor refactor

* fix(j-s): tests

* fix(j-s): how we init the param date

* chore: nx format:write update dirty files

* fix(j-s): add date as a request body property rather than url param

---------

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 Jan 14, 2025
1 parent 4785092 commit 006bb01
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ export class InternalCaseController {
return this.internalCaseService.archive()
}

@Post('cases/postHearingArrangements')
async postHearingArrangements(
@Body() { date }: { date: Date },
): Promise<void> {
this.logger.debug(
`Post internal summary of all cases that have court hearing arrangement at ${date}`,
)

const cases = await this.internalCaseService.getCaseHearingArrangements(
new Date(date),
)
await this.eventService.postDailyHearingArrangementEvents(date, cases)
}

@Get('cases/indictments/defendant/:defendantNationalId')
@ApiOkResponse({
type: Case,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,29 @@ export class InternalCaseService {
return { caseArchived: true }
}

async getCaseHearingArrangements(date: Date): Promise<Case[]> {
const startOfDay = new Date(date.setHours(0, 0, 0, 0))
const endOfDay = new Date(date.setHours(23, 59, 59, 999))

return this.caseModel.findAll({
include: [
{
model: DateLog,
as: 'dateLogs',
where: {
date_type: ['ARRAIGNMENT_DATE', 'COURT_DATE'],
date: {
[Op.gte]: startOfDay,
[Op.lte]: endOfDay,
},
},
required: true,
},
],
order: [[{ model: DateLog, as: 'dateLogs' }, 'date', 'ASC']],
})
}

async deliverProsecutorToCourt(
theCase: Case,
user: TUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import type { User as TUser } from '@island.is/judicial-system/types'
import {
CaseState,
CaseType,
DefendantEventType,
indictmentCases,
investigationCases,
restrictionCases,
Expand All @@ -39,7 +38,6 @@ import {

import { nowFactory } from '../../factories'
import { defenderRule, prisonSystemStaffRule } from '../../guards'
import { DefendantService } from '../defendant'
import { EventService } from '../event'
import { User } from '../user'
import { TransitionCaseDto } from './dto/transitionCase.dto'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,51 @@ export class EventService {
}
}

async postDailyHearingArrangementEvents(date: Date, cases: Case[]) {
const title = `:judge: Fyrirtökur ${formatDate(date)}`

const arrangementTexts = cases.map((theCase) => {
return `>${theCase.courtCaseNumber}: ${
formatDate(
DateLog.courtDate(theCase.dateLogs)?.date ??
DateLog.arraignmentDate(theCase.dateLogs)?.date,
'p',
) ?? date
}`
})

const arrangementSummary =
arrangementTexts.length > 0
? arrangementTexts.join('\n')
: '>Engar fyrirtökur á dagskrá'

try {
if (!this.config.url) {
return
}

await fetch(`${this.config.url}`, {
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*${title}*\n${arrangementSummary}`,
},
},
],
}),
})
} catch (error) {
this.logger.error(`Failed to post court hearing arrangement summary`, {
error,
})
}
}

async postErrorEvent(
message: string,
info: { [key: string]: string | boolean | Date | undefined },
Expand Down
47 changes: 40 additions & 7 deletions apps/judicial-system/scheduler/src/app/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fetch from 'node-fetch'

import { Inject, Injectable } from '@nestjs/common'
import { BadGatewayException, Inject, Injectable } from '@nestjs/common'

import { type Logger, LOGGER_PROVIDER } from '@island.is/logging'
import { type ConfigType } from '@island.is/nest/config'
Expand All @@ -24,12 +24,8 @@ export class AppService {
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

async run() {
this.logger.info('Scheduler starting')

const startTime = now()

this.messageService
private addMessagesForIndictmentsWaitingForConfirmationToQueue() {
return this.messageService
.sendMessagesToQueue([
{
type: MessageType.NOTIFICATION_DISPATCH,
Expand All @@ -42,6 +38,10 @@ export class AppService {
// Tolerate failure, but log
this.logger.error('Failed to dispatch notifications', { reason }),
)
}

private async archiveCases() {
const startTime = now()

let done = false

Expand Down Expand Up @@ -76,6 +76,39 @@ export class AppService {
!done &&
minutesBetween(startTime, now()) < this.config.timeToLiveMinutes
)
}

private async postDailyHearingArrangementSummary() {
const today = now()
try {
const res = await fetch(
`${this.config.backendUrl}/api/internal/cases/postHearingArrangements`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
authorization: `Bearer ${this.config.backendAccessToken}`,
},
body: JSON.stringify({ date: today }),
},
)

if (!res.ok) {
throw new BadGatewayException(
'Unexpected error occurred while fetching cases',
)
}
} catch (error) {
throw new BadGatewayException(`Failed to fetch cases: ${error.message}`)
}
}

async run() {
this.logger.info('Scheduler starting')

await this.addMessagesForIndictmentsWaitingForConfirmationToQueue()
await this.archiveCases()
await this.postDailyHearingArrangementSummary()

this.logger.info('Scheduler done')
}
Expand Down
29 changes: 26 additions & 3 deletions apps/judicial-system/scheduler/src/app/test/run.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('AppService - Run', () => {
beforeEach(() => {
mockNow.mockClear()
mockFetch.mockClear()

mockNow.mockReturnValue(new Date('2020-01-01T00:01:00.000Z'))

givenWhenThen = async (): Promise<Then> => {
Expand Down Expand Up @@ -75,7 +76,7 @@ describe('AppService - Run', () => {
body: { type: 'INDICTMENTS_WAITING_FOR_CONFIRMATION' },
},
])
expect(fetch).toHaveBeenCalledTimes(3)
expect(fetch).toHaveBeenCalledTimes(4)
expect(fetch).toHaveBeenCalledWith(
`${appModuleConfig().backendUrl}/api/internal/cases/archive`,
{
Expand All @@ -86,6 +87,19 @@ describe('AppService - Run', () => {
},
},
)
expect(fetch).toHaveBeenCalledWith(
`${
appModuleConfig().backendUrl
}/api/internal/cases/postHearingArrangements`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
authorization: `Bearer ${appModuleConfig().backendAccessToken}`,
},
body: JSON.stringify({ date: new Date('2020-01-01T00:01:00.000Z') }),
},
)
})
})

Expand All @@ -102,8 +116,17 @@ describe('AppService - Run', () => {
await givenWhenThen()
})

it('should call the backend twice', () => {
expect(fetch).toHaveBeenCalledTimes(2)
it('should attempt archiving twice', () => {
expect(fetch).toHaveBeenNthCalledWith(
1,
`${appModuleConfig().backendUrl}/api/internal/cases/archive`,
expect.any(Object),
)
expect(fetch).toHaveBeenNthCalledWith(
2,
`${appModuleConfig().backendUrl}/api/internal/cases/archive`,
expect.any(Object),
)
})
})

Expand Down

0 comments on commit 006bb01

Please sign in to comment.