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

fix(j-s): Defender Case File Access #15070

Merged
merged 3 commits into from
Jun 4, 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 @@ -245,6 +245,11 @@ export const include: Includeable[] = [
as: 'appealJudge3',
include: [{ model: Institution, as: 'institution' }],
},
{
model: User,
as: 'indictmentReviewer',
include: [{ model: Institution, as: 'institution' }],
},
{
model: Case,
as: 'parentCase',
Expand Down Expand Up @@ -289,11 +294,6 @@ export const include: Includeable[] = [
where: { commentType: { [Op.in]: commentTypes } },
},
{ model: Notification, as: 'notifications' },
{
model: User,
as: 'indictmentReviewer',
include: [{ model: Institution, as: 'institution' }],
},
]

export const order: OrderItem[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ import {
CaseState,
CommentType,
DateType,
EventType,
NotificationType,
UserRole,
} from '@island.is/judicial-system/types'

import { nowFactory, uuidFactory } from '../../factories'
import { AwsS3Service } from '../aws-s3'
import { Defendant, DefendantService } from '../defendant'
import { EventLog } from '../event-log'
import {
CaseFile,
defenderCaseFileCategoriesForRestrictionAndInvestigationCases,
Expand Down Expand Up @@ -111,6 +113,7 @@ export interface LimitedAccessUpdateCase
| 'appealRulingDecision'
> {}

const eventTypes = Object.values(EventType)
const dateTypes = Object.values(DateType)
const commentTypes = Object.values(CommentType)

Expand Down Expand Up @@ -186,6 +189,14 @@ export const include: Includeable[] = [
],
},
},
{
model: EventLog,
as: 'eventLogs',
required: false,
where: { eventType: { [Op.in]: eventTypes } },
order: [['created', 'ASC']],
separate: true,
},
{
model: DateLog,
as: 'dateLogs',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import {
isCompletedCase,
isDefenceUser,
isIndictmentCase,
isInvestigationCase,
isPrisonSystemUser,
isRestrictionCase,
isRequestCase,
User,
} from '@island.is/judicial-system/types'

Expand Down Expand Up @@ -47,30 +46,32 @@ export class LimitedAccessViewCaseFileGuard implements CanActivate {
throw new InternalServerErrorException('Missing case file')
}

if (isCompletedCase(theCase.state) && caseFile.category) {
if (isDefenceUser(user)) {
if (
(isRestrictionCase(theCase.type) ||
isInvestigationCase(theCase.type)) &&
defenderCaseFileCategoriesForRestrictionAndInvestigationCases.includes(
caseFile.category,
)
) {
return true
}
if (isDefenceUser(user) && caseFile.category) {
if (
isRequestCase(theCase.type) &&
isCompletedCase(theCase.state) &&
defenderCaseFileCategoriesForRestrictionAndInvestigationCases.includes(
caseFile.category,
)
) {
return true
}

if (
isIndictmentCase(theCase.type) &&
defenderCaseFileCategoriesForIndictmentCases.includes(caseFile.category)
) {
return true
}
}

if (
isIndictmentCase(theCase.type) &&
defenderCaseFileCategoriesForIndictmentCases.includes(
caseFile.category,
)
) {
return true
}
} else if (isPrisonSystemUser(user)) {
if (caseFile.category === CaseFileCategory.APPEAL_RULING) {
return true
}
if (isPrisonSystemUser(user)) {
if (
isCompletedCase(theCase.state) &&
caseFile.category &&
caseFile.category === CaseFileCategory.APPEAL_RULING
) {
return true
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ describe('Limited Access View Case File Guard', () => {
)

describe.each(indictmentCases)('for %s cases', (type) => {
describe.each(completedCaseStates)('in state %s', (state) => {
describe.each(Object.values(CaseState))('in state %s', (state) => {
const allowedCaseFileCategories = [
CaseFileCategory.COURT_RECORD,
CaseFileCategory.RULING,
Expand Down Expand Up @@ -208,36 +208,6 @@ describe('Limited Access View Case File Guard', () => {
})
})
})

describe.each(
Object.keys(CaseState).filter(
(state) => !completedCaseStates.includes(state as CaseState),
),
)('in state %s', (state) => {
describe.each(Object.keys(CaseFileCategory))(
'a defender can not view %s',
(category) => {
let then: Then

beforeEach(() => {
mockRequest.mockImplementationOnce(() => ({
user: { role: UserRole.DEFENDER },
case: { type, state },
caseFile: { category },
}))

then = givenWhenThen()
})

it('should throw ForbiddenException', () => {
expect(then.error).toBeInstanceOf(ForbiddenException)
expect(then.error.message).toBe(
`Forbidden for ${UserRole.DEFENDER}`,
)
})
},
)
})
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,7 @@ import { PresignedPost } from './models/presignedPost.model'
import { SignedUrl } from './models/signedUrl.model'
import { FileService } from './file.service'

@UseGuards(
JwtAuthGuard,
RolesGuard,
LimitedAccessCaseExistsGuard,
CaseCompletedGuard,
)
@UseGuards(JwtAuthGuard, RolesGuard, LimitedAccessCaseExistsGuard)
@Controller('api/case/:caseId/limitedAccess')
@ApiTags('files')
export class LimitedAccessFileController {
Expand All @@ -64,6 +59,7 @@ export class LimitedAccessFileController {
@UseGuards(
new CaseTypeGuard([...restrictionCases, ...investigationCases]),
CaseWriteGuard,
CaseCompletedGuard,
)
@RolesRules(defenderRule)
@Post('file/url')
Expand All @@ -84,6 +80,7 @@ export class LimitedAccessFileController {
@UseGuards(
new CaseTypeGuard([...restrictionCases, ...investigationCases]),
CaseWriteGuard,
CaseCompletedGuard,
LimitedAccessWriteCaseFileGuard,
)
@RolesRules(defenderRule)
Expand All @@ -92,7 +89,7 @@ export class LimitedAccessFileController {
type: CaseFile,
description: 'Creates a new case file',
})
async createCaseFile(
createCaseFile(
@Param('caseId') caseId: string,
@CurrentHttpUser() user: User,
@CurrentCase() theCase: Case,
Expand Down Expand Up @@ -126,6 +123,7 @@ export class LimitedAccessFileController {
@UseGuards(
new CaseTypeGuard([...restrictionCases, ...investigationCases]),
CaseWriteGuard,
CaseCompletedGuard,
CaseFileExistsGuard,
LimitedAccessWriteCaseFileGuard,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {
restrictionCases,
} from '@island.is/judicial-system/types'

import { CaseTypeGuard, CaseWriteGuard } from '../../../case'
import {
CaseCompletedGuard,
CaseTypeGuard,
CaseWriteGuard,
} from '../../../case'
import { LimitedAccessWriteCaseFileGuard } from '../../guards/limitedAccessWriteCaseFile.guard'
import { LimitedAccessFileController } from '../../limitedAccessFile.controller'

Expand All @@ -19,12 +23,13 @@ describe('LimitedAccessFileController - Create case file guards', () => {
})

it('should have the right guard configuration', () => {
expect(guards).toHaveLength(3)
expect(guards).toHaveLength(4)
expect(guards[0]).toBeInstanceOf(CaseTypeGuard)
expect(guards[0]).toEqual({
allowedCaseTypes: [...restrictionCases, ...investigationCases],
})
expect(new guards[1]()).toBeInstanceOf(CaseWriteGuard)
expect(new guards[2]()).toBeInstanceOf(LimitedAccessWriteCaseFileGuard)
expect(new guards[2]()).toBeInstanceOf(CaseCompletedGuard)
expect(new guards[3]()).toBeInstanceOf(LimitedAccessWriteCaseFileGuard)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {
restrictionCases,
} from '@island.is/judicial-system/types'

import { CaseTypeGuard, CaseWriteGuard } from '../../../case'
import {
CaseCompletedGuard,
CaseTypeGuard,
CaseWriteGuard,
} from '../../../case'
import { LimitedAccessFileController } from '../../limitedAccessFile.controller'

describe('LimitedAccessFileController - Create presigned post guards', () => {
Expand All @@ -18,11 +22,12 @@ describe('LimitedAccessFileController - Create presigned post guards', () => {
})

it('should have the right guard configuration', () => {
expect(guards).toHaveLength(2)
expect(guards).toHaveLength(3)
expect(guards[0]).toBeInstanceOf(CaseTypeGuard)
expect(guards[0]).toEqual({
allowedCaseTypes: [...restrictionCases, ...investigationCases],
})
expect(new guards[1]()).toBeInstanceOf(CaseWriteGuard)
expect(new guards[2]()).toBeInstanceOf(CaseCompletedGuard)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {
restrictionCases,
} from '@island.is/judicial-system/types'

import { CaseTypeGuard, CaseWriteGuard } from '../../../case'
import {
CaseCompletedGuard,
CaseTypeGuard,
CaseWriteGuard,
} from '../../../case'
import { CaseFileExistsGuard } from '../../guards/caseFileExists.guard'
import { LimitedAccessWriteCaseFileGuard } from '../../guards/limitedAccessWriteCaseFile.guard'
import { LimitedAccessFileController } from '../../limitedAccessFile.controller'
Expand All @@ -20,13 +24,14 @@ describe('LimitedAccessFileController - Delete case file guards', () => {
})

it('should have the right guard configuration', () => {
expect(guards).toHaveLength(4)
expect(guards).toHaveLength(5)
expect(guards[0]).toBeInstanceOf(CaseTypeGuard)
expect(guards[0]).toEqual({
allowedCaseTypes: [...restrictionCases, ...investigationCases],
})
expect(new guards[1]()).toBeInstanceOf(CaseWriteGuard)
expect(new guards[2]()).toBeInstanceOf(CaseFileExistsGuard)
expect(new guards[3]()).toBeInstanceOf(LimitedAccessWriteCaseFileGuard)
expect(new guards[2]()).toBeInstanceOf(CaseCompletedGuard)
expect(new guards[3]()).toBeInstanceOf(CaseFileExistsGuard)
expect(new guards[4]()).toBeInstanceOf(LimitedAccessWriteCaseFileGuard)
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JwtAuthGuard, RolesGuard } from '@island.is/judicial-system/auth'

import { CaseCompletedGuard, LimitedAccessCaseExistsGuard } from '../../../case'
import { LimitedAccessCaseExistsGuard } from '../../../case'
import { LimitedAccessFileController } from '../../limitedAccessFile.controller'

describe('LimitedAccessFileController - guards', () => {
Expand All @@ -12,10 +12,9 @@ describe('LimitedAccessFileController - guards', () => {
})

it('should have the right guard configuration', () => {
expect(guards).toHaveLength(4)
expect(guards).toHaveLength(3)
expect(new guards[0]()).toBeInstanceOf(JwtAuthGuard)
expect(new guards[1]()).toBeInstanceOf(RolesGuard)
expect(new guards[2]()).toBeInstanceOf(LimitedAccessCaseExistsGuard)
expect(new guards[3]()).toBeInstanceOf(CaseCompletedGuard)
})
})
Loading