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

feat(j-s): Subpoena delivery and endpoint for updates #15918

Merged
merged 41 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e646d74
feat(j-s): New endpoints for subpoenas in xrd-api
unakb Aug 16, 2024
1e5dab7
Merge branch 'main' into j-s/xrd-api-subpoena
unakb Aug 20, 2024
3d33df2
test(j-s): Tests
unakb Aug 20, 2024
9ae4c85
Merge branch 'j-s/xrd-api-subpoena' of https://github.com/island-is/i…
unakb Aug 20, 2024
a9d9703
feat(j-s): WIP create subpoena
unakb Aug 26, 2024
96a36ba
feat(j-s): New subpoena table
unakb Aug 28, 2024
4788d6e
Merge branch 'j-s/create-subpoena' into j-s/subpoena-table
unakb Aug 28, 2024
d12e022
Merge branch 'main' into j-s/subpoena-table
unakb Sep 4, 2024
8620d53
chore(j-s): Add institution addresses to db
unakb Sep 4, 2024
ccaaf0d
chore(j-s): Use institution from db for subpoena
unakb Sep 4, 2024
a20369f
Merge branch 'j-s/add-district-court-address-to-institution' into j-s…
unakb Sep 4, 2024
cb45d4c
chore(j-s): Subpoena work
unakb Sep 5, 2024
9e512d3
Merge branch 'main' into j-s/subpoena-table
unakb Sep 9, 2024
7251a4e
fix(j-s): remove unused code
unakb Sep 9, 2024
ee8ae0b
Update case.service.ts
unakb Sep 9, 2024
947e41d
Update message.service.ts
unakb Sep 9, 2024
e966cd7
fix(j-s): Renaming and exception handling
unakb Sep 9, 2024
9f6c346
Merge branch 'main' into j-s/xrd-api-subpoena
unakb Sep 9, 2024
9a0b5ae
Merge branch 'j-s/xrd-api-subpoena' into j-s/subpoena-table
unakb Sep 9, 2024
8f3dd84
Delete 20240815104210-update-explanatory_comment.js
unakb Sep 9, 2024
30ac3c9
fix(j-s): Complete rewrite to create a new subpoena module to handle …
unakb Sep 10, 2024
6db30c0
Cleanup
unakb Sep 10, 2024
748a696
fix(j-s): More cleanup
unakb Sep 10, 2024
6279d57
feat(j-s): Update defendant info
unakb Sep 10, 2024
025e54b
feat(j-s): Add guards
unakb Sep 11, 2024
1a2aedf
fix(j-s): cleanup
unakb Sep 11, 2024
f43ba1e
Update app.service.ts
unakb Sep 11, 2024
78b5f1e
Update app.service.ts
unakb Sep 11, 2024
f93fc87
Merge branch 'main' into j-s/subpoena-table
unakb Sep 11, 2024
b244860
fix(j-s): Removed unused files
unakb Sep 11, 2024
a989d0f
Merge branch 'j-s/subpoena-table' of https://github.com/island-is/isl…
unakb Sep 11, 2024
1758ef1
Update subpoena.dto.ts
unakb Sep 13, 2024
dd65a70
fix(j-s): Feedback resolved
unakb Sep 16, 2024
f5e8c56
fix(j-s): cleanup
unakb Sep 16, 2024
7822377
Merge branch 'main' into j-s/subpoena-table
unakb Sep 16, 2024
2319c9a
Merge branch 'main' into j-s/subpoena-table
gudjong Sep 16, 2024
70c5c73
fix(j-s): review fixes
unakb Sep 16, 2024
1703f0b
Merge branch 'j-s/subpoena-table' of https://github.com/island-is/isl…
unakb Sep 16, 2024
ee68a4f
feat(j-s): Add field for registered by
unakb Sep 16, 2024
459c9dd
Merge branch 'main' into j-s/subpoena-table
unakb Sep 16, 2024
d6180f0
Merge branch 'main' into j-s/subpoena-table
kodiakhq[bot] Sep 16, 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,68 @@
'use strict'

unakb marked this conversation as resolved.
Show resolved Hide resolved
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface.createTable(
'subpoena',
{
id: {
type: Sequelize.UUID,
primaryKey: true,
allowNull: false,
defaultValue: Sequelize.UUIDV4,
},
created: {
type: 'TIMESTAMP WITH TIME ZONE',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false,
},
modified: {
type: 'TIMESTAMP WITH TIME ZONE',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false,
},
defendant_id: {
type: Sequelize.UUID,
references: {
model: 'defendant',
key: 'id',
},
allowNull: false,
},
case_id: {
type: Sequelize.UUID,
references: {
model: 'case',
key: 'id',
},
allowNull: true,
},
subpoena_id: {
type: Sequelize.STRING,
allowNull: true,
},
acknowledged: {
type: Sequelize.BOOLEAN,
allowNull: true,
},
acknowledged_date: {
type: 'TIMESTAMP WITH TIME ZONE',
allowNull: true,
},
comment: {
type: Sequelize.STRING,
unakb marked this conversation as resolved.
Show resolved Hide resolved
allowNull: true,
},
},
{ transaction: t },
),
)
},

down: (queryInterface) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface.dropTable('subpoena', { transaction: t }),
)
},
}
2 changes: 2 additions & 0 deletions apps/judicial-system/backend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
notificationModuleConfig,
PoliceModule,
policeModuleConfig,
SubpoenaModule,
UserModule,
userModuleConfig,
} from './modules'
Expand All @@ -50,6 +51,7 @@ import { SequelizeConfigService } from './sequelizeConfig.service'
NotificationModule,
PoliceModule,
EventLogModule,
SubpoenaModule,
ProblemModule.forRoot({ logAllErrors: true }),
ConfigModule.forRoot({
isGlobal: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ export class CaseService {
]
}

private addMessagesForSubmittedIndicitmentCaseToQueue(
private addMessagesForSubmittedIndictmentCaseToQueue(
unakb marked this conversation as resolved.
Show resolved Hide resolved
theCase: Case,
user: TUser,
): Promise<void> {
Expand Down Expand Up @@ -1181,7 +1181,7 @@ export class CaseService {
await this.addMessagesForCompletedCaseToQueue(updatedCase, user)
}
} else if (updatedCase.state === CaseState.SUBMITTED && isIndictment) {
await this.addMessagesForSubmittedIndicitmentCaseToQueue(
await this.addMessagesForSubmittedIndictmentCaseToQueue(
updatedCase,
user,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,22 @@ export class DefendantService {
): Promise<Defendant> {
const formattedNationalId = formatNationalId(defendantNationalId)

const defendant = await this.defendantModel.findOne({
where: {
caseId,
[Op.or]: [
{ nationalId: formattedNationalId },
{ nationalId: defendantNationalId },
],
},
})

if (!defendant) {
throw new InternalServerErrorException(
unakb marked this conversation as resolved.
Show resolved Hide resolved
`Could not find defendant with national id ${defendantNationalId} for case ${caseId}`,
)
}

const [numberOfAffectedRows, defendants] = await this.defendantModel.update(
update,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ export class InternalDefendantController {
@Patch('defense/:defendantNationalId')
@ApiOkResponse({
type: Defendant,
description: 'Assigns defense choice to defendant',
description: 'Updates defendant information by case and national id',
})
async assignDefender(
async updateDefendant(
@Param('caseId') caseId: string,
@Param('defendantNationalId') defendantNationalId: string,
@CurrentCase() theCase: Case,
@Body() updatedDefendantChoice: UpdateDefendantDto,
): Promise<Defendant> {
this.logger.debug(`Assigning defense choice to defendant in case ${caseId}`)
this.logger.debug(`Updating defendant info for ${caseId}`)

const updatedDefendant = await this.defendantService.updateByNationalId(
theCase.id,
Expand Down
1 change: 1 addition & 0 deletions apps/judicial-system/backend/src/app/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export { CourtModule } from './court/court.module'
export { AwsS3Module } from './aws-s3/awsS3.module'
export { EventModule } from './event/event.module'
export { EventLogModule } from './event-log/eventLog.module'
export { SubpoenaModule } from './subpoena/subpoena.module'
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ export class NotificationService {
]
} else {
messages = [this.getNotificationMessage(type, user, theCase)]
theCase.defendants?.forEach((defendant) => {
messages.push({
type: MessageType.DELIVERY_TO_POLICE_SUBPOENA,
unakb marked this conversation as resolved.
Show resolved Hide resolved
user,
caseId: theCase.id,
elementId: defendant.id,
})
})
}
break
case NotificationType.HEADS_UP:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger'

export class CreateSubpoenaResponse {
@ApiProperty({ type: String })
subpoenaId!: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ import { CaseState, CaseType } from '@island.is/judicial-system/types'

import { nowFactory } from '../../factories'
import { AwsS3Service } from '../aws-s3'
import { Case } from '../case'
import { Defendant } from '../defendant/models/defendant.model'
import { EventService } from '../event'
import { UploadPoliceCaseFileDto } from './dto/uploadPoliceCaseFile.dto'
import { CreateSubpoenaResponse } from './models/createSubpoena.response'
import { PoliceCaseFile } from './models/policeCaseFile.model'
import { PoliceCaseInfo } from './models/policeCaseInfo.model'
import { UploadPoliceCaseFileResponse } from './models/uploadPoliceCaseFile.response'
Expand Down Expand Up @@ -505,4 +508,72 @@ export class PoliceService {
return false
})
}

async createSubpoena(
workingCase: Case,
defendant: Defendant,
subpoena: string,
user: User,
): Promise<CreateSubpoenaResponse> {
const { courtCaseNumber, dateLogs, prosecutor, policeCaseNumbers, court } =
workingCase
const { nationalId: defendantNationalId } = defendant
const { name: actor } = user

const documentName = `Fyrirkall í máli ${workingCase.courtCaseNumber}`
const arraignmentInfo = dateLogs?.find(
(dateLog) => dateLog.dateType === 'ARRAIGNMENT_DATE',
)
try {
const res = await this.fetchPoliceCaseApi(
`${this.xRoadPath}/CreateSubpoena`,
{
method: 'POST',
headers: {
accept: '*/*',
'Content-Type': 'application/json',
'X-Road-Client': this.config.clientId,
'X-API-KEY': this.config.policeApiKey,
},
agent: this.agent,
body: JSON.stringify({
documentName: documentName,
documentBase64: subpoena,
courtRegistrationDate: arraignmentInfo?.date,
prosecutorSsn: prosecutor?.nationalId,
prosecutedSsn: defendantNationalId,
courtAddress: court?.address,
courtRoomNumber: arraignmentInfo?.location || '',
courtCeremony: 'Þingfesting',
lokeCaseNumber: policeCaseNumbers?.[0],
courtCaseNumber: courtCaseNumber,
fileTypeCode: 'BRTNG',
}),
} as RequestInit,
)

if (!res.ok) {
throw await res.json()
}

const subpoenaId = await res.json()
return { subpoenaId }
} catch (error) {
this.logger.error(`Failed create subpoena for case ${workingCase.id}`, {
error,
})

this.eventService.postErrorEvent(
'Failed to create subpoena',
{
caseId: workingCase.id,
defendantId: defendant?.nationalId,
actor,
},
error,
)

throw error
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IsNotEmpty, IsObject } from 'class-validator'

import { ApiProperty } from '@nestjs/swagger'

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

export class DeliverDto {
@IsNotEmpty()
@IsObject()
@ApiProperty({ type: Object })
readonly user!: User
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator'

import { ApiPropertyOptional } from '@nestjs/swagger'

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

export class UpdateSubpoenaDto {
@IsOptional()
@IsBoolean()
@ApiPropertyOptional({ type: Boolean })
readonly acknowledged?: boolean

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly comment?: string

@IsOptional()
@IsEnum(DefenderChoice)
@ApiPropertyOptional({ enum: DefenderChoice })
readonly defenderChoice?: DefenderChoice

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly defenderNationalId?: string

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly defenderName?: string

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly defenderEmail?: string

@IsOptional()
@IsString()
@ApiPropertyOptional({ type: String })
readonly defenderPhoneNumber?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createParamDecorator } from '@nestjs/common'

import { Subpoena } from '../models/subpoena.model'

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

import { SubpoenaService } from '../subpoena.service'

@Injectable()
export class SubpoenaExistsGuard implements CanActivate {
constructor(private readonly subpoenaService: SubpoenaService) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest()

const subpoenaId = request.params.subpoenaId

if (!subpoenaId) {
throw new BadRequestException('Missing subpoena id')
}

request.subpoena = await this.subpoenaService.findBySubpoenaId(subpoenaId)

return true
}
}
Loading
Loading