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

chore(j-s): Prison users access to appeal case files #15844

Merged
merged 15 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -99,8 +99,8 @@ import {
prosecutorUpdateRule,
publicProsecutorStaffUpdateRule,
} from './guards/rolesRules'
import { CaseInterceptor } from './interceptors/case.interceptor'
import { CaseListInterceptor } from './interceptors/caseList.interceptor'
import { CompletedAppealAccessedInterceptor } from './interceptors/completedAppealAccessed.interceptor'
import { Case } from './models/case.model'
import { SignatureConfirmationResponse } from './models/signatureConfirmation.response'
import { transitionCase } from './state/case.state'
Expand Down Expand Up @@ -465,7 +465,7 @@ export class CaseController {
)
@Get('case/:caseId')
@ApiOkResponse({ type: Case, description: 'Gets an existing case' })
@UseInterceptors(CaseInterceptor)
@UseInterceptors(CompletedAppealAccessedInterceptor)
getById(@Param('caseId') caseId: string, @CurrentCase() theCase: Case): Case {
this.logger.debug(`Getting case ${caseId} by id`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class LimitedAccessCaseExistsGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest()

const caseId = request.params.caseId
const caseId: string = request.params.caseId

if (!caseId) {
throw new BadRequestException('Missing case id')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'

import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common'

import {
CaseAppealState,
CaseFileCategory,
isDefenceUser,
isPrisonStaffUser,
isPrisonSystemUser,
User,
} from '@island.is/judicial-system/types'

import { Case } from '../models/case.model'

@Injectable()
export class CaseFileInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<Case> {
const request = context.switchToHttp().getRequest()
const user: User = request.user

return next.handle().pipe(
map((data: Case) => {
if (isDefenceUser(user)) {
return data
}

if (
isPrisonStaffUser(user) ||
data.appealState !== CaseAppealState.COMPLETED
oddsson marked this conversation as resolved.
Show resolved Hide resolved
) {
data.caseFiles?.splice(0, data.caseFiles.length)
} else if (isPrisonSystemUser(user)) {
data.caseFiles?.splice(
0,
data.caseFiles.length,
...data.caseFiles.filter(
(cf) => cf.category === CaseFileCategory.APPEAL_RULING,
),
)
}

return data
}),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { EventLogService } from '../../event-log'
import { Case } from '../models/case.model'

@Injectable()
export class CaseInterceptor implements NestInterceptor {
export class CompletedAppealAccessedInterceptor implements NestInterceptor {
constructor(private readonly eventLogService: EventLogService) {}

intercept(context: ExecutionContext, next: CallHandler): Observable<Case> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ import { CaseWriteGuard } from './guards/caseWrite.guard'
import { LimitedAccessCaseExistsGuard } from './guards/limitedAccessCaseExists.guard'
import { RequestSharedWithDefenderGuard } from './guards/requestSharedWithDefender.guard'
import { defenderTransitionRule, defenderUpdateRule } from './guards/rolesRules'
import { CaseInterceptor } from './interceptors/case.interceptor'
import { CaseFileInterceptor } from './interceptors/caseFile.interceptor'
import { CompletedAppealAccessedInterceptor } from './interceptors/completedAppealAccessed.interceptor'
import { Case } from './models/case.model'
import { transitionCase } from './state/case.state'
import {
Expand Down Expand Up @@ -85,7 +86,7 @@ export class LimitedAccessCaseController {
type: Case,
description: 'Gets a limited set of properties of an existing case',
})
@UseInterceptors(CaseInterceptor)
@UseInterceptors(CompletedAppealAccessedInterceptor, CaseFileInterceptor)
async getById(
@Param('caseId') caseId: string,
@CurrentCase() theCase: Case,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export const defenderCaseFileCategoriesForIndictmentCases = [
CaseFileCategory.PROSECUTOR_CASE_FILE,
CaseFileCategory.DEFENDANT_CASE_FILE,
]

export const prisonAdminCaseFileCategories = [CaseFileCategory.APPEAL_RULING]
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import {
} from '@nestjs/common'

import {
CaseFileCategory,
isCompletedCase,
isDefenceUser,
isIndictmentCase,
isPrisonSystemUser,
isPrisonAdminUser,
isRequestCase,
User,
} from '@island.is/judicial-system/types'
Expand All @@ -21,6 +20,7 @@ import { CaseFile } from '../models/file.model'
import {
defenderCaseFileCategoriesForIndictmentCases,
defenderCaseFileCategoriesForRestrictionAndInvestigationCases,
prisonAdminCaseFileCategories,
} from './caseFileCategory'

@Injectable()
Expand Down Expand Up @@ -65,14 +65,13 @@ export class LimitedAccessViewCaseFileGuard implements CanActivate {
}
}

if (isPrisonSystemUser(user)) {
if (
isCompletedCase(theCase.state) &&
caseFile.category &&
caseFile.category === CaseFileCategory.APPEAL_RULING
) {
return true
}
if (
caseFile.category &&
isCompletedCase(theCase.state) &&
isPrisonAdminUser(user) &&
prisonAdminCaseFileCategories.includes(caseFile.category)
) {
return true
}

throw new ForbiddenException(`Forbidden for ${user.role}`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,27 +229,19 @@ describe('Limited Access View Case File Guard', () => {
describe.each(allowedCaseFileCategories)(
'prison system users can view %s',
(category) => {
let thenPrison: Then
let thenPrisonAdmin: Then

beforeEach(() => {
mockRequest.mockImplementationOnce(() => ({
user: prisonUser,
case: { type, state },
caseFile: { category },
}))
mockRequest.mockImplementationOnce(() => ({
user: prisonAdminUser,
case: { type, state },
caseFile: { category },
}))

thenPrison = givenWhenThen()
thenPrisonAdmin = givenWhenThen()
})

it('should activate', () => {
expect(thenPrison.result).toBe(true)
expect(thenPrisonAdmin.result).toBe(true)
})
},
Expand Down
2 changes: 2 additions & 0 deletions libs/judicial-system/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ export {
isCourtOfAppealsUser,
prisonSystemRoles,
isPrisonSystemUser,
isPrisonStaffUser,
defenceRoles,
isDefenceUser,
isAdminUser,
isCoreUser,
isPrisonAdminUser,
isPublicProsecutor,
} from './lib/user'
export type { User } from './lib/user'
Expand Down
20 changes: 10 additions & 10 deletions libs/judicial-system/types/src/lib/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ export enum CaseFileCategory {
CASE_FILE_RECORD = 'CASE_FILE_RECORD',
PROSECUTOR_CASE_FILE = 'PROSECUTOR_CASE_FILE',
DEFENDANT_CASE_FILE = 'DEFENDANT_CASE_FILE',
PROSECUTOR_APPEAL_BRIEF = 'PROSECUTOR_APPEAL_BRIEF',
DEFENDANT_APPEAL_BRIEF = 'DEFENDANT_APPEAL_BRIEF',
PROSECUTOR_APPEAL_BRIEF_CASE_FILE = 'PROSECUTOR_APPEAL_BRIEF_CASE_FILE',
DEFENDANT_APPEAL_BRIEF_CASE_FILE = 'DEFENDANT_APPEAL_BRIEF_CASE_FILE',
PROSECUTOR_APPEAL_STATEMENT = 'PROSECUTOR_APPEAL_STATEMENT',
DEFENDANT_APPEAL_STATEMENT = 'DEFENDANT_APPEAL_STATEMENT',
PROSECUTOR_APPEAL_STATEMENT_CASE_FILE = 'PROSECUTOR_APPEAL_STATEMENT_CASE_FILE',
DEFENDANT_APPEAL_STATEMENT_CASE_FILE = 'DEFENDANT_APPEAL_STATEMENT_CASE_FILE',
PROSECUTOR_APPEAL_CASE_FILE = 'PROSECUTOR_APPEAL_CASE_FILE',
DEFENDANT_APPEAL_CASE_FILE = 'DEFENDANT_APPEAL_CASE_FILE',
PROSECUTOR_APPEAL_BRIEF = 'PROSECUTOR_APPEAL_BRIEF', // Sækjandi: Kæruskjal til Landsréttar
DEFENDANT_APPEAL_BRIEF = 'DEFENDANT_APPEAL_BRIEF', // Verjandi: Kæruskjal til Landsréttar
PROSECUTOR_APPEAL_BRIEF_CASE_FILE = 'PROSECUTOR_APPEAL_BRIEF_CASE_FILE', // Sækjandi: Fylgigögn kæruskjals til Landsréttar
DEFENDANT_APPEAL_BRIEF_CASE_FILE = 'DEFENDANT_APPEAL_BRIEF_CASE_FILE', // Verjandi: Fylgigögn kæruskjals til Landsréttar
PROSECUTOR_APPEAL_STATEMENT = 'PROSECUTOR_APPEAL_STATEMENT', // Sækjandi: Greinargerð
DEFENDANT_APPEAL_STATEMENT = 'DEFENDANT_APPEAL_STATEMENT', // Verjandi: Greinargerð
PROSECUTOR_APPEAL_STATEMENT_CASE_FILE = 'PROSECUTOR_APPEAL_STATEMENT_CASE_FILE', // Sækjandi: Fylgigögn greinargerðar
DEFENDANT_APPEAL_STATEMENT_CASE_FILE = 'DEFENDANT_APPEAL_STATEMENT_CASE_FILE', // Verjandi: Fylgigögn greinargerðar
PROSECUTOR_APPEAL_CASE_FILE = 'PROSECUTOR_APPEAL_CASE_FILE', // Sækjandi: Viðbótargögn við kæru til Landsréttar
DEFENDANT_APPEAL_CASE_FILE = 'DEFENDANT_APPEAL_CASE_FILE', // Verjandi: Viðbótargögn við kæru til Landsréttar
APPEAL_COURT_RECORD = 'APPEAL_COURT_RECORD',
APPEAL_RULING = 'APPEAL_RULING',
}
14 changes: 14 additions & 0 deletions libs/judicial-system/types/src/lib/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ export const isPrisonSystemUser = (user?: InstitutionUser): boolean => {
)
}

export const isPrisonAdminUser = (user: InstitutionUser): boolean =>
Boolean(
user.role &&
prisonSystemRoles.includes(user.role) &&
user.institution?.type === InstitutionType.PRISON_ADMIN,
)

export const isPrisonStaffUser = (user: InstitutionUser): boolean =>
Boolean(
user.role &&
prisonSystemRoles.includes(user.role) &&
user.institution?.type === InstitutionType.PRISON,
)

export const defenceRoles: string[] = [UserRole.DEFENDER]

export const isDefenceUser = (user?: InstitutionUser): boolean => {
Expand Down
Loading