Skip to content

Commit

Permalink
Merge branch 'main' into fix/mock-users-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Dec 16, 2024
2 parents 8fead2b + e6a12da commit 4be2e96
Show file tree
Hide file tree
Showing 35 changed files with 712 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,17 @@ export class BackendService extends DataSource<{ req: Request }> {
)
}

limitedAccessUpdateDefendant(
caseId: string,
defendantId: string,
updateDefendant: unknown,
): Promise<Defendant> {
return this.patch(
`case/${caseId}/limitedAccess/defendant/${defendantId}`,
updateDefendant,
)
}

deleteDefendant(
caseId: string,
defendantId: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import { Module } from '@nestjs/common'

import { CivilClaimantResolver } from './civilClaimant.resolver'
import { DefendantResolver } from './defendant.resolver'
import { LimitedAccessDefendantResolver } from './limitedAccessDefendant.resolver'

@Module({
providers: [DefendantResolver, CivilClaimantResolver],
providers: [
DefendantResolver,
CivilClaimantResolver,
LimitedAccessDefendantResolver,
],
})
export class DefendantModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
DefendantPlea,
DefenderChoice,
Gender,
PunishmentType,
ServiceRequirement,
SubpoenaType,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -114,4 +115,9 @@ export class UpdateDefendantInput {
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly isSentToPrisonAdmin?: boolean

@Allow()
@IsOptional()
@Field(() => PunishmentType, { nullable: true })
readonly punishmentType?: PunishmentType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Inject, UseGuards } from '@nestjs/common'
import { Args, Context, Mutation, Resolver } from '@nestjs/graphql'

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

import {
AuditedAction,
AuditTrailService,
} from '@island.is/judicial-system/audit-trail'
import {
CurrentGraphQlUser,
JwtGraphQlAuthGuard,
} from '@island.is/judicial-system/auth'
import type { User } from '@island.is/judicial-system/types'

import { BackendService } from '../backend'
import { UpdateDefendantInput } from './dto/updateDefendant.input'
import { Defendant } from './models/defendant.model'

@UseGuards(JwtGraphQlAuthGuard)
@Resolver()
export class LimitedAccessDefendantResolver {
constructor(
private readonly auditTrailService: AuditTrailService,
@Inject(LOGGER_PROVIDER)
private readonly logger: Logger,
) {}

@Mutation(() => Defendant, { nullable: true })
limitedAccessUpdateDefendant(
@Args('input', { type: () => UpdateDefendantInput })
input: UpdateDefendantInput,
@CurrentGraphQlUser() user: User,
@Context('dataSources')
{ backendService }: { backendService: BackendService },
): Promise<Defendant> {
const { caseId, defendantId, ...updateDefendant } = input
this.logger.debug(
`Updating limitedAccess defendant ${defendantId} for case ${caseId}`,
)

return this.auditTrailService.audit(
user.id,
AuditedAction.UPDATE_DEFENDANT,
backendService.limitedAccessUpdateDefendant(
caseId,
defendantId,
updateDefendant,
),
defendantId,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
DefendantPlea,
DefenderChoice,
Gender,
PunishmentType,
ServiceRequirement,
SubpoenaType,
} from '@island.is/judicial-system/types'
Expand All @@ -15,6 +16,7 @@ registerEnumType(DefendantPlea, { name: 'DefendantPlea' })
registerEnumType(ServiceRequirement, { name: 'ServiceRequirement' })
registerEnumType(DefenderChoice, { name: 'DefenderChoice' })
registerEnumType(SubpoenaType, { name: 'SubpoenaType' })
registerEnumType(PunishmentType, { name: 'PunishmentType' })

@ObjectType()
export class Defendant {
Expand Down Expand Up @@ -107,4 +109,7 @@ export class Defendant {

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

@Field(() => PunishmentType, { nullable: true })
readonly punishmentType?: PunishmentType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

module.exports = {
async up(queryInterface, Sequelize) {
return queryInterface.sequelize.transaction((t) =>
Promise.all([
queryInterface.addColumn(
'defendant',
'punishment_type',
{
type: Sequelize.STRING,
allowNull: true,
},
{ transaction: t },
),
]),
)
},
async down(queryInterface, Sequelize) {
return queryInterface.sequelize.transaction((t) =>
queryInterface.removeColumn('defendant', 'punishment_type', {
transaction: t,
}),
)
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CivilClaimantService } from './civilClaimant.service'
import { DefendantController } from './defendant.controller'
import { DefendantService } from './defendant.service'
import { InternalDefendantController } from './internalDefendant.controller'
import { LimitedAccessDefendantController } from './limitedAccessDefendant.controller'

@Module({
imports: [
Expand All @@ -25,6 +26,7 @@ import { InternalDefendantController } from './internalDefendant.controller'
DefendantController,
InternalDefendantController,
CivilClaimantController,
LimitedAccessDefendantController,
],
providers: [DefendantService, CivilClaimantService],
exports: [DefendantService, CivilClaimantService],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DefendantPlea,
DefenderChoice,
Gender,
PunishmentType,
ServiceRequirement,
SubpoenaType,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -149,4 +150,9 @@ export class UpdateDefendantDto {
@IsBoolean()
@ApiPropertyOptional({ type: Boolean })
readonly isSentToPrisonAdmin?: boolean

@IsOptional()
@IsEnum(PunishmentType)
@ApiPropertyOptional({ enum: PunishmentType })
readonly punishmentType?: PunishmentType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RolesRule, RulesType } from '@island.is/judicial-system/auth'
import { UserRole } from '@island.is/judicial-system/types'

import { UpdateDefendantDto } from '../dto/updateDefendant.dto'

const limitedAccessFields: (keyof UpdateDefendantDto)[] = ['punishmentType']

// Allows prison staff to update a specific set of fields for defendant
export const prisonSystemStaffUpdateRule: RolesRule = {
role: UserRole.PRISON_SYSTEM_STAFF,
type: RulesType.FIELD,
dtoFields: limitedAccessFields,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
Body,
Controller,
Inject,
Param,
Patch,
UseGuards,
} from '@nestjs/common'
import { ApiOkResponse, ApiTags } from '@nestjs/swagger'

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

import {
CurrentHttpUser,
JwtAuthGuard,
RolesGuard,
RolesRules,
} from '@island.is/judicial-system/auth'
import { type User } from '@island.is/judicial-system/types'

import { Case, CaseExistsGuard, CurrentCase } from '../case'
import { UpdateDefendantDto } from './dto/updateDefendant.dto'
import { CurrentDefendant } from './guards/defendant.decorator'
import { DefendantExistsGuard } from './guards/defendantExists.guard'
import { prisonSystemStaffUpdateRule } from './guards/rolesRules'
import { Defendant } from './models/defendant.model'
import { DefendantService } from './defendant.service'

@Controller('api/case/:caseId/limitedAccess/defendant')
@ApiTags('limited access defendant')
@UseGuards(JwtAuthGuard, RolesGuard)
export class LimitedAccessDefendantController {
constructor(
private readonly defendantService: DefendantService,
@Inject(LOGGER_PROVIDER) private readonly logger: Logger,
) {}

@UseGuards(CaseExistsGuard, DefendantExistsGuard)
@RolesRules(prisonSystemStaffUpdateRule)
@Patch(':defendantId')
@ApiOkResponse({
type: Defendant,
description: 'Updates a defendant',
})
updateDefendant(
@Param('caseId') caseId: string,
@Param('defendantId') defendantId: string,
@CurrentHttpUser() user: User,
@CurrentCase() theCase: Case,
@CurrentDefendant() defendant: Defendant,
@Body() updateDto: Pick<UpdateDefendantDto, 'punishmentType'>,
): Promise<Defendant> {
this.logger.debug(
`Updating limitedAccess defendant ${defendantId} of case ${caseId}`,
)
return this.defendantService.updateRequestCaseDefendant(
theCase,
defendant,
updateDto,
user,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DefendantPlea,
DefenderChoice,
Gender,
PunishmentType,
ServiceRequirement,
SubpoenaType,
} from '@island.is/judicial-system/types'
Expand Down Expand Up @@ -201,6 +202,14 @@ export class Defendant extends Model {
@ApiPropertyOptional({ type: Boolean })
isSentToPrisonAdmin?: boolean

@Column({
type: DataType.ENUM,
allowNull: true,
values: Object.values(PunishmentType),
})
@ApiPropertyOptional({ enum: PunishmentType })
punishmentType?: PunishmentType

@HasMany(() => DefendantEventLog, { foreignKey: 'defendantId' })
@ApiPropertyOptional({ type: () => DefendantEventLog, isArray: true })
eventLogs?: DefendantEventLog[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { CivilClaimantService } from '../civilClaimant.service'
import { DefendantController } from '../defendant.controller'
import { DefendantService } from '../defendant.service'
import { InternalDefendantController } from '../internalDefendant.controller'
import { LimitedAccessDefendantController } from '../limitedAccessDefendant.controller'
import { CivilClaimant } from '../models/civilClaimant.model'
import { Defendant } from '../models/defendant.model'
import { DefendantEventLog } from '../models/defendantEventLog.model'
Expand All @@ -32,6 +33,7 @@ export const createTestingDefendantModule = async () => {
imports: [ConfigModule.forRoot({ load: [sharedAuthModuleConfig] })],
controllers: [
DefendantController,
LimitedAccessDefendantController,
InternalDefendantController,
CivilClaimantController,
],
Expand Down Expand Up @@ -108,6 +110,11 @@ export const createTestingDefendantModule = async () => {
InternalDefendantController,
)

const limitedAccessDefendantController =
defendantModule.get<LimitedAccessDefendantController>(
LimitedAccessDefendantController,
)

const civilClaimantModel = await defendantModule.resolve<
typeof CivilClaimant
>(getModelToken(CivilClaimant))
Expand All @@ -129,6 +136,7 @@ export const createTestingDefendantModule = async () => {
defendantService,
defendantController,
internalDefendantController,
limitedAccessDefendantController,
civilClaimantService,
civilClaimantController,
civilClaimantModel,
Expand Down
Loading

0 comments on commit 4be2e96

Please sign in to comment.