Skip to content

Commit

Permalink
feat(j-s): API endpoint to update subpoena (#15051)
Browse files Browse the repository at this point in the history
* fix(j-s): Digital mailbox api config

* fix(j-s): Config

* fix(j-s): Added missing config value

* Update judicial-system-xrd-robot-api.ts

* Update app.config.ts

* Update yaml

* chore(j-s): Lawyers lib and controller added to digital mailbox api

* Moving some files around

* fix(j-s): cleanup

* chore(j-s): Cleanup

* import types as types

* Update lawyers.service.ts

* Update defender.controller.ts

* chore(j-s): New functionality for subpoenas in API

* Update case.controller.ts

* chore(j-s): Continued API work

* Update 20240530132001-update-defendant.js

* chore(j-s): Retrieve ssn from ids token

* fix(j-s): national id handling for defender

* chore: nx format:write update dirty files

* Update case.controller.ts

* Update internalDefendant.controller.ts

* fix(j-s): Test

* Update SelectDefender.tsx

* fix(j-s): Guards test

* Update 20240514111505-update-defendant.js

* Update internalDefendant.controller.ts

* fix(j-s): cleanup

* fix(j-s): Validation

* Update subpoena.response.ts

* fix(j-s): Controller decorators

* Update internalDefendant.controller.ts

* chore(j-s): Cleanups and handling different national id formats

* fix(j-s): Feedback fixes

* Update case.controller.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 Jun 4, 2024
1 parent d3ce693 commit 1566034
Show file tree
Hide file tree
Showing 36 changed files with 651 additions and 283 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Field, ID, InputType } from '@nestjs/graphql'

import {
DefendantPlea,
DefenderChoice,
Gender,
ServiceRequirement,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -68,11 +69,6 @@ export class UpdateDefendantInput {
@Field(() => String, { nullable: true })
readonly defenderPhoneNumber?: string

@Allow()
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly defendantWaivesRightToCounsel?: boolean

@Allow()
@IsOptional()
@Field(() => DefendantPlea, { nullable: true })
Expand All @@ -87,4 +83,9 @@ export class UpdateDefendantInput {
@IsOptional()
@Field(() => String, { nullable: true })
readonly verdictViewDate?: string

@Allow()
@IsOptional()
@Field(() => DefenderChoice, { nullable: true })
readonly defenderChoice?: DefenderChoice
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql'

import {
DefendantPlea,
DefenderChoice,
Gender,
ServiceRequirement,
} from '@island.is/judicial-system/types'

registerEnumType(Gender, { name: 'Gender' })
registerEnumType(DefendantPlea, { name: 'DefendantPlea' })
registerEnumType(ServiceRequirement, { name: 'ServiceRequirement' })
registerEnumType(DefenderChoice, { name: 'DefenderChoice' })

@ObjectType()
export class Defendant {
Expand Down Expand Up @@ -54,9 +56,6 @@ export class Defendant {
@Field(() => String, { nullable: true })
readonly defenderPhoneNumber?: string

@Field(() => Boolean, { nullable: true })
readonly defendantWaivesRightToCounsel?: boolean

@Field(() => DefendantPlea, { nullable: true })
readonly defendantPlea?: DefendantPlea

Expand All @@ -68,4 +67,7 @@ export class Defendant {

@Field(() => String, { nullable: true })
readonly verdictAppealDeadline?: string

@Field(() => DefenderChoice, { nullable: true })
readonly defenderChoice?: DefenderChoice
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface
.addColumn(
'defendant',
'defender_choice',
{
type: Sequelize.STRING,
allowNull: true,
},
{ transaction: t },
)
.then(() =>
queryInterface.sequelize.query(
`UPDATE "defendant" SET defender_choice = 'WAIVE' WHERE defendant_waives_right_to_counsel = true;`,
{ transaction: t },
),
)
.then(() =>
queryInterface.removeColumn(
'defendant',
'defendant_waives_right_to_counsel',
{ transaction: t },
),
),
)
},

down: (queryInterface, Sequelize) => {
return queryInterface.sequelize.transaction((t) =>
queryInterface
.addColumn(
'defendant',
'defendant_waives_right_to_counsel',
{
type: Sequelize.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction: t },
)
.then(() =>
queryInterface.sequelize.query(
`UPDATE "defendant" SET defendant_waives_right_to_counsel = true WHERE defender_choice = 'WAIVE';`,
{ transaction: t },
),
)
.then(() =>
queryInterface.removeColumn('defendant', 'defender_choice', {
transaction: t,
}),
),
)
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ export class InternalCaseController {
@Body() internalCasesDto: InternalCasesDto,
): Promise<Case[]> {
this.logger.debug('Getting all indictment cases')
const nationalId = formatNationalId(internalCasesDto.nationalId)

return this.internalCaseService.getIndictmentCases(nationalId)
return this.internalCaseService.getIndictmentCases(
internalCasesDto.nationalId,
)
}

@Post('cases/indictment/:caseId')
Expand All @@ -95,9 +96,11 @@ export class InternalCaseController {
@Body() internalCasesDto: InternalCasesDto,
): Promise<Case | null> {
this.logger.debug(`Getting indictment case ${caseId}`)
const nationalId = formatNationalId(internalCasesDto.nationalId)

return this.internalCaseService.getIndictmentCase(caseId, nationalId)
return this.internalCaseService.getIndictmentCase(
caseId,
internalCasesDto.nationalId,
)
}

@UseGuards(CaseExistsGuard)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { FormatMessage, IntlService } from '@island.is/cms-translations'
import { type Logger, LOGGER_PROVIDER } from '@island.is/logging'
import type { ConfigType } from '@island.is/nest/config'

import { formatCaseType } from '@island.is/judicial-system/formatters'
import {
formatCaseType,
formatNationalId,
} from '@island.is/judicial-system/formatters'
import {
CaseFileCategory,
CaseOrigin,
Expand Down Expand Up @@ -1048,6 +1051,8 @@ export class InternalCaseService {
}

async getIndictmentCases(nationalId: string): Promise<Case[]> {
const formattedNationalId = formatNationalId(nationalId)

return this.caseModel.findAll({
include: [
{ model: Defendant, as: 'defendants' },
Expand All @@ -1057,7 +1062,10 @@ export class InternalCaseService {
attributes: ['id', 'courtCaseNumber', 'type', 'state'],
where: {
type: CaseType.INDICTMENT,
'$defendants.national_id$': nationalId,
[Op.or]: [
{ '$defendants.national_id$': nationalId },
{ '$defendants.national_id$': formattedNationalId },
],
},
})
}
Expand All @@ -1066,6 +1074,10 @@ export class InternalCaseService {
caseId: string,
nationalId: string,
): Promise<Case | null> {
// The national id could be without a hyphen or with a hyphen so we need to
// search for both
const formattedNationalId = formatNationalId(nationalId)

const caseById = await this.caseModel.findOne({
include: [
{ model: Defendant, as: 'defendants' },
Expand All @@ -1078,7 +1090,10 @@ export class InternalCaseService {
where: {
type: CaseType.INDICTMENT,
id: caseId,
'$defendants.national_id$': nationalId,
[Op.or]: [
{ '$defendants.national_id$': nationalId },
{ '$defendants.national_id$': formattedNationalId },
],
},
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
Inject,
Injectable,
InternalServerErrorException,
NotFoundException,
} from '@nestjs/common'
import { InjectModel } from '@nestjs/sequelize'

import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'

import { formatNationalId } from '@island.is/judicial-system/formatters'
import {
CaseMessage,
MessageService,
Expand Down Expand Up @@ -195,6 +197,37 @@ export class DefendantService {
return updatedDefendant
}

async updateByNationalId(
caseId: string,
defendantNationalId: string,
update: UpdateDefendantDto,
): Promise<Defendant> {
const formattedNationalId = formatNationalId(defendantNationalId)

const [numberOfAffectedRows, defendants] = await this.defendantModel.update(
update,
{
where: {
caseId,
[Op.or]: [
{ national_id: formattedNationalId },
{ national_id: defendantNationalId },
],
},
returning: true,
},
)

const updatedDefendant = this.getUpdatedDefendant(
numberOfAffectedRows,
defendants,
defendants[0].id,
caseId,
)

return updatedDefendant
}

async delete(
theCase: Case,
defendantId: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator'

import { ApiPropertyOptional } from '@nestjs/swagger'

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

export class CreateDefendantDto {
@IsOptional()
Expand Down Expand Up @@ -56,7 +56,7 @@ export class CreateDefendantDto {
readonly defenderPhoneNumber?: string

@IsOptional()
@IsBoolean()
@ApiPropertyOptional({ type: Boolean })
readonly defendantWaivesRightToCounsel?: boolean
@IsEnum(DefenderChoice)
@ApiPropertyOptional({ enum: DefenderChoice })
readonly defenderChoice?: DefenderChoice
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ApiPropertyOptional } from '@nestjs/swagger'

import {
DefendantPlea,
DefenderChoice,
Gender,
ServiceRequirement,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -60,9 +61,9 @@ export class UpdateDefendantDto {
readonly defenderPhoneNumber?: string

@IsOptional()
@IsBoolean()
@ApiPropertyOptional({ type: Boolean })
readonly defendantWaivesRightToCounsel?: boolean
@IsEnum(DefenderChoice)
@ApiPropertyOptional({ enum: DefenderChoice })
readonly defenderChoice?: DefenderChoice

@IsOptional()
@IsEnum(DefendantPlea)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import {
Controller,
Inject,
Param,
Patch,
Post,
UseGuards,
} from '@nestjs/common'
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger'
import { ApiCreatedResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger'

import type { Logger } from '@island.is/logging'
import { LOGGER_PROVIDER } from '@island.is/logging'
Expand All @@ -19,26 +20,26 @@ import {

import { Case, CaseExistsGuard, CurrentCase } from '../case'
import { DeliverDefendantToCourtDto } from './dto/deliverDefendantToCourt.dto'
import { UpdateDefendantDto } from './dto/updateDefendant.dto'
import { CurrentDefendant } from './guards/defendant.decorator'
import { DefendantExistsGuard } from './guards/defendantExists.guard'
import { Defendant } from './models/defendant.model'
import { DeliverResponse } from './models/deliver.response'
import { DefendantService } from './defendant.service'

@Controller(
`api/internal/case/:caseId/${
messageEndpoint[MessageType.DELIVERY_TO_COURT_DEFENDANT]
}/:defendantId`,
)
@Controller('api/internal/case/:caseId')
@ApiTags('internal defendants')
@UseGuards(TokenGuard, CaseExistsGuard, DefendantExistsGuard)
@UseGuards(TokenGuard, CaseExistsGuard)
export class InternalDefendantController {
constructor(
private readonly defendantService: DefendantService,
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

@Post()
@UseGuards(DefendantExistsGuard)
@Post(
`${messageEndpoint[MessageType.DELIVERY_TO_COURT_DEFENDANT]}/:defendantId`,
)
@ApiCreatedResponse({
type: DeliverResponse,
description: 'Delivers a case file to court',
Expand All @@ -60,4 +61,26 @@ export class InternalDefendantController {
deliverDefendantToCourtDto.user,
)
}

@Patch('defense/:defendantNationalId')
@ApiOkResponse({
type: Defendant,
description: 'Assigns defense choice to defendant',
})
async assignDefender(
@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}`)

const updatedDefendant = await this.defendantService.updateByNationalId(
theCase.id,
defendantNationalId,
updatedDefendantChoice,
)

return updatedDefendant
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'

import {
DefendantPlea,
DefenderChoice,
Gender,
ServiceRequirement,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -94,9 +95,13 @@ export class Defendant extends Model {
@ApiPropertyOptional({ type: String })
defenderPhoneNumber?: string

@Column({ type: DataType.BOOLEAN, allowNull: false, defaultValue: false })
@ApiProperty({ type: Boolean })
defendantWaivesRightToCounsel!: boolean
@Column({
type: DataType.ENUM,
allowNull: true,
values: Object.values(DefenderChoice),
})
@ApiPropertyOptional({ enum: DefenderChoice })
defenderChoice?: DefenderChoice

@Column({
type: DataType.ENUM,
Expand Down
Loading

0 comments on commit 1566034

Please sign in to comment.