diff --git a/apps/judicial-system/backend/src/app/modules/case/case.controller.ts b/apps/judicial-system/backend/src/app/modules/case/case.controller.ts index cca384ac525a..4978748add3a 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.controller.ts @@ -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' @@ -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`) diff --git a/apps/judicial-system/backend/src/app/modules/case/guards/limitedAccessCaseExists.guard.ts b/apps/judicial-system/backend/src/app/modules/case/guards/limitedAccessCaseExists.guard.ts index 460480edf5f8..f92e78361b74 100644 --- a/apps/judicial-system/backend/src/app/modules/case/guards/limitedAccessCaseExists.guard.ts +++ b/apps/judicial-system/backend/src/app/modules/case/guards/limitedAccessCaseExists.guard.ts @@ -14,7 +14,7 @@ export class LimitedAccessCaseExistsGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest() - const caseId = request.params.caseId + const caseId: string = request.params.caseId if (!caseId) { throw new BadRequestException('Missing case id') diff --git a/apps/judicial-system/backend/src/app/modules/case/interceptors/caseFile.interceptor.ts b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseFile.interceptor.ts new file mode 100644 index 000000000000..d7d74fb30a5c --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseFile.interceptor.ts @@ -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 { + 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 + ) { + 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 + }), + ) + } +} diff --git a/apps/judicial-system/backend/src/app/modules/case/interceptors/case.interceptor.ts b/apps/judicial-system/backend/src/app/modules/case/interceptors/completedAppealAccessed.interceptor.ts similarity index 94% rename from apps/judicial-system/backend/src/app/modules/case/interceptors/case.interceptor.ts rename to apps/judicial-system/backend/src/app/modules/case/interceptors/completedAppealAccessed.interceptor.ts index 6beab2bc3915..5ff8d84bff3f 100644 --- a/apps/judicial-system/backend/src/app/modules/case/interceptors/case.interceptor.ts +++ b/apps/judicial-system/backend/src/app/modules/case/interceptors/completedAppealAccessed.interceptor.ts @@ -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 { diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.controller.ts index 7e17c55bab85..809dcfc390cc 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.controller.ts @@ -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 { @@ -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, diff --git a/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts b/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts index 5455ad7976b0..2d8d88353f35 100644 --- a/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts +++ b/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts @@ -22,3 +22,5 @@ export const defenderCaseFileCategoriesForIndictmentCases = [ CaseFileCategory.PROSECUTOR_CASE_FILE, CaseFileCategory.DEFENDANT_CASE_FILE, ] + +export const prisonAdminCaseFileCategories = [CaseFileCategory.APPEAL_RULING] diff --git a/apps/judicial-system/backend/src/app/modules/file/guards/limitedAccessViewCaseFile.guard.ts b/apps/judicial-system/backend/src/app/modules/file/guards/limitedAccessViewCaseFile.guard.ts index 3526675d6902..a8c2f8295ea7 100644 --- a/apps/judicial-system/backend/src/app/modules/file/guards/limitedAccessViewCaseFile.guard.ts +++ b/apps/judicial-system/backend/src/app/modules/file/guards/limitedAccessViewCaseFile.guard.ts @@ -7,11 +7,10 @@ import { } from '@nestjs/common' import { - CaseFileCategory, isCompletedCase, isDefenceUser, isIndictmentCase, - isPrisonSystemUser, + isPrisonAdminUser, isRequestCase, User, } from '@island.is/judicial-system/types' @@ -21,6 +20,7 @@ import { CaseFile } from '../models/file.model' import { defenderCaseFileCategoriesForIndictmentCases, defenderCaseFileCategoriesForRestrictionAndInvestigationCases, + prisonAdminCaseFileCategories, } from './caseFileCategory' @Injectable() @@ -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}`) diff --git a/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts b/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts index dd31ac1d7816..e4e7672dc2d6 100644 --- a/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts @@ -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) }) }, diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 27dcae8b586d..cf873e6f07cc 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -28,10 +28,12 @@ export { isCourtOfAppealsUser, prisonSystemRoles, isPrisonSystemUser, + isPrisonStaffUser, defenceRoles, isDefenceUser, isAdminUser, isCoreUser, + isPrisonAdminUser, isPublicProsecutor, } from './lib/user' export type { User } from './lib/user' diff --git a/libs/judicial-system/types/src/lib/file.ts b/libs/judicial-system/types/src/lib/file.ts index 44f65118a9a1..ae687d066896 100644 --- a/libs/judicial-system/types/src/lib/file.ts +++ b/libs/judicial-system/types/src/lib/file.ts @@ -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', } diff --git a/libs/judicial-system/types/src/lib/user.ts b/libs/judicial-system/types/src/lib/user.ts index ba7a5a6ec417..8c0dcb478e20 100644 --- a/libs/judicial-system/types/src/lib/user.ts +++ b/libs/judicial-system/types/src/lib/user.ts @@ -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 => {