Skip to content

Commit

Permalink
Merge branch 'main' into feat/new-primary-school-reason-data-implemen…
Browse files Browse the repository at this point in the history
…tation
  • Loading branch information
veronikasif committed Oct 8, 2024
2 parents 5db8a2b + 6ce1b55 commit 8eb057b
Show file tree
Hide file tree
Showing 112 changed files with 2,226 additions and 2,351 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/pullrequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,14 @@ jobs:
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
- uses: reviewdog/action-shellcheck@v1
with:
ignore_paths: >-
node_modules
apps/native/app/android
severity: warning
github_token: ${{ secrets.github_token }}
reporter: github-pr-review
fail_on_error: true
level: info
exclude: >-
*/node_modules/*
formatting:
needs:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Base } from 'infra/src/dsl/xroad'
import { Base64 } from 'js-base64'
import { Includeable, Sequelize } from 'sequelize'
import { Transaction } from 'sequelize/types'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ApiProperty } from '@nestjs/swagger'

import { formatDate } from '@island.is/judicial-system/formatters'
import { DateType } from '@island.is/judicial-system/types'
import {
DateType,
isSuccessfulServiceStatus,
} from '@island.is/judicial-system/types'

import { InternalCaseResponse } from './internal/internalCase.response'
import { Groups } from './shared/groups.model'
Expand Down Expand Up @@ -41,7 +44,10 @@ export class CaseResponse {
caseId: internalCase.id,
data: {
caseNumber: `${t.caseNumber} ${internalCase.courtCaseNumber}`,
hasBeenServed: subpoenas.length > 0 ? subpoenas[0].acknowledged : false,
hasBeenServed:
subpoenas.length > 0
? isSuccessfulServiceStatus(subpoenas[0].serviceStatus)
: false,
groups: [
{
label: t.defendant,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DefenderChoice,
Gender,
Institution,
ServiceStatus,
User,
} from '@island.is/judicial-system/types'

Expand Down Expand Up @@ -42,5 +43,5 @@ interface DateLog {
interface Subpoena {
id: string
subpoenaId: string
acknowledged: boolean
serviceStatus?: ServiceStatus
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import {
formatDate,
normalizeAndFormatNationalId,
} from '@island.is/judicial-system/formatters'
import { DateType, DefenderChoice } from '@island.is/judicial-system/types'
import {
DateType,
DefenderChoice,
isSuccessfulServiceStatus,
} from '@island.is/judicial-system/types'

import { InternalCaseResponse } from './internal/internalCase.response'
import { Groups } from './shared/groups.model'
Expand Down Expand Up @@ -59,6 +63,12 @@ class SubpoenaData {

@ApiProperty({ type: Boolean })
hasBeenServed?: boolean

@ApiProperty({ type: Boolean })
hasChosenDefender?: boolean

@ApiProperty({ enum: DefenderChoice })
defaultDefenderChoice?: DefenderChoice
}

export class SubpoenaResponse {
Expand Down Expand Up @@ -87,9 +97,11 @@ export class SubpoenaResponse {
)

const waivedRight = defendantInfo?.defenderChoice === DefenderChoice.WAIVE
const hasDefender = defendantInfo?.defenderName !== undefined
const subpoena = defendantInfo?.subpoenas ?? []
const hasBeenServed = subpoena[0]?.acknowledged ?? false
const hasDefender = defendantInfo?.defenderName !== null
const subpoenas = defendantInfo?.subpoenas ?? []
const hasBeenServed =
subpoenas.length > 0 &&
isSuccessfulServiceStatus(subpoenas[0].serviceStatus)
const canChangeDefenseChoice = !waivedRight && !hasDefender

const subpoenaDateLog = internalCase.dateLogs?.find(
Expand All @@ -108,6 +120,11 @@ export class SubpoenaResponse {
title: t.subpoena,
subtitle: courtNameAndAddress,
hasBeenServed: hasBeenServed,
hasChosenDefender: Boolean(
defendantInfo?.defenderChoice &&
defendantInfo.defenderChoice !== DefenderChoice.DELAY,
),
defaultDefenderChoice: DefenderChoice.DELAY,
alerts: [
...(hasBeenServed
? [
Expand Down
10 changes: 6 additions & 4 deletions apps/service-portal/src/screens/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
DocumentsPaths,
DocumentLine,
DocumentLineV3,
useDocumentList,
useDocumentListV3,
} from '@island.is/service-portal/documents'
import {
LinkResolver,
Expand All @@ -41,9 +41,7 @@ import { useFeatureFlagClient } from '@island.is/react/feature-flags'

export const Dashboard: FC<React.PropsWithChildren<unknown>> = () => {
const { userInfo } = useAuth()
const { filteredDocuments, data, loading } = useDocumentList({
defaultPageSize: 8,
})

const { data: organizations } = useOrganizations()
const { formatMessage } = useLocale()
const { width } = useWindowSize()
Expand All @@ -56,6 +54,10 @@ export const Dashboard: FC<React.PropsWithChildren<unknown>> = () => {
// Versioning feature flag. Remove after feature is live.
const [v3Enabled, setV3Enabled] = useState<boolean>()

const { filteredDocuments, data, loading } = useDocumentListV3({
defaultPageSize: 8,
})

const featureFlagClient = useFeatureFlagClient()
useEffect(() => {
const isFlagEnabled = async () => {
Expand Down
2 changes: 2 additions & 0 deletions apps/services/auth/admin-api/infra/auth-admin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const serviceSetup = (): ServiceBuilder<'services-auth-admin-api'> => {
.secrets({
ZENDESK_CONTACT_FORM_EMAIL: '/k8s/api/ZENDESK_CONTACT_FORM_EMAIL',
ZENDESK_CONTACT_FORM_TOKEN: '/k8s/api/ZENDESK_CONTACT_FORM_TOKEN',
ZENDESK_WEBHOOK_SECRET_GENERAL_MANDATE:
'/k8s/services-auth/ZENDESK_WEBHOOK_SECRET_GENERAL_MANDATE',
CLIENT_SECRET_ENCRYPTION_KEY:
'/k8s/services-auth/admin-api/CLIENT_SECRET_ENCRYPTION_KEY',
IDENTITY_SERVER_CLIENT_SECRET:
Expand Down
1 change: 0 additions & 1 deletion apps/services/auth/admin-api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ConfigModule } from '@nestjs/config'
import { SequelizeModule } from '@nestjs/sequelize'

import {
DelegationApiUserSystemNotificationConfig,
DelegationConfig,
SequelizeConfigService,
} from '@island.is/auth-api-lib'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,34 @@ import {
UseGuards,
} from '@nestjs/common'
import { ApiTags } from '@nestjs/swagger'
import flatMap from 'lodash/flatMap'

import {
BypassAuth,
CurrentUser,
IdsUserGuard,
Scopes,
ScopesGuard,
User,
ZendeskAuthGuard,
} from '@island.is/auth-nest-tools'
import {
CreatePaperDelegationDto,
DelegationAdminCustomDto,
DelegationAdminCustomService,
DelegationDTO,
ZendeskWebhookInputDto,
} from '@island.is/auth-api-lib'
import { Documentation } from '@island.is/nest/swagger'
import { Audit, AuditService } from '@island.is/nest/audit'
import { DelegationAdminScopes } from '@island.is/auth/scopes'
import flatMap from 'lodash/flatMap'
import { isDefined } from '@island.is/shared/utils'

import env from '../../../environments/environment'

const namespace = '@island.is/auth/delegation-admin'

@UseGuards(IdsUserGuard, ScopesGuard)
@Scopes(DelegationAdminScopes.read)
@ApiTags('delegation-admin')
@Controller('delegation-admin')
@Audit({ namespace })
Expand All @@ -43,6 +47,7 @@ export class DelegationAdminController {
) {}

@Get()
@Scopes(DelegationAdminScopes.read)
@Documentation({
response: { status: 200, type: DelegationAdminCustomDto },
request: {
Expand Down Expand Up @@ -91,6 +96,18 @@ export class DelegationAdminController {
)
}

@BypassAuth()
@UseGuards(new ZendeskAuthGuard(env.zendeskGeneralMandateWebhookSecret))
@Post('/zendesk')
@Documentation({
response: { status: 200 },
})
async createByZendeskId(
@Body() { id }: ZendeskWebhookInputDto,
): Promise<void> {
await this.delegationAdminService.createDelegationByZendeskId(id)
}

@Delete(':delegationId')
@Scopes(DelegationAdminScopes.admin)
@Documentation({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import request from 'supertest'
import bodyParser from 'body-parser'

import {
getRequestMethod,
Expand All @@ -11,9 +12,11 @@ import { User } from '@island.is/auth-nest-tools'
import { FixtureFactory } from '@island.is/services/auth/testing'
import { createCurrentUser } from '@island.is/testing/fixtures'
import { DelegationAdminScopes } from '@island.is/auth/scopes'
import { SequelizeConfigService } from '@island.is/auth-api-lib'
import { DelegationDTO, SequelizeConfigService } from '@island.is/auth-api-lib'
import { DelegationAdminCustomService } from '@island.is/auth-api-lib'

import { AppModule } from '../../../app.module'
import { includeRawBodyMiddleware } from '@island.is/infra-nest-server'

describe('withoutAuth and permissions', () => {
async function formatUrl(app: TestApp, endpoint: string, user?: User) {
Expand Down Expand Up @@ -132,4 +135,79 @@ describe('withoutAuth and permissions', () => {
app.cleanUp()
},
)

describe('POST /delegation-admin/zendesk', () => {
let app: TestApp
let server: request.SuperTest<request.Test>
let delegationAdminService: DelegationAdminCustomService

beforeEach(async () => {
app = await setupAppWithoutAuth({
AppModule,
SequelizeConfigService,
dbType: 'postgres',
beforeServerStart: async (app) => {
await new Promise((resolve) =>
resolve(app.use(includeRawBodyMiddleware())),
)
},
})

server = request(app.getHttpServer())

delegationAdminService = app.get(DelegationAdminCustomService)

jest
.spyOn(delegationAdminService, 'createDelegationByZendeskId')
.mockImplementation(() => Promise.resolve())
})

afterEach(() => {
app.cleanUp()
})

it('POST /delegation-admin/zendesk should return 403 Forbidden when request signature is invalid.', async () => {
// Act
const res = await getRequestMethod(
server,
'POST',
)('/delegation-admin/zendesk')
.send({
id: 'Incorrect body',
})
.set(
'x-zendesk-webhook-signature',
'6sUtGV8C8OdoGgCdsV2xRm3XeskZ33Bc5124RiAK4Q4=',
)
.set('x-zendesk-webhook-signature-timestamp', '2024-10-02T14:21:04Z')

// Assert
expect(res.status).toEqual(403)
expect(res.body).toMatchObject({
status: 403,
type: 'https://httpstatuses.org/403',
title: 'Forbidden',
detail: 'Forbidden resource',
})
})

it('POST /delegation-admin/zendesk should return 200 when signature is valid', async () => {
// Act
const res = await getRequestMethod(
server,
'POST',
)('/delegation-admin/zendesk')
.send({
id: 'test',
})
.set(
'x-zendesk-webhook-signature',
'ntgS06VGgd4z73lHjIpC2sk9azhRNi4u1xkXF/KPKTs=',
)
.set('x-zendesk-webhook-signature-timestamp', '2024-10-02T14:21:04Z')

// Assert
expect(res.status).toEqual(200)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,25 @@ describe('DelegationAdmin - With authentication', () => {
const mockZendeskService = (
toNationalId: string,
fromNationalId: string,
info?: {
tags?: string[]
status?: TicketStatus
},
) => {
const { tags, status } = {
tags: [DELEGATION_TAG],
status: TicketStatus.Solved,
...info,
}

zendeskServiceApiSpy = jest
.spyOn(zendeskService, 'getTicket')
.mockImplementation((ticketId: string) => {
return new Promise((resolve) =>
resolve({
id: ticketId,
tags: [DELEGATION_TAG],
status: TicketStatus.Solved,
tags: tags,
status: status,
custom_fields: [
{
id: ZENDESK_CUSTOM_FIELDS.DelegationToReferenceId,
Expand Down Expand Up @@ -328,5 +338,26 @@ describe('DelegationAdmin - With authentication', () => {
// Assert
expect(res.status).toEqual(400)
})

it('POST /delegation-admin should not create delegation with incorrect zendesk ticket status', async () => {
// Arrange
mockZendeskService(toNationalId, fromNationalId, {
status: TicketStatus.Open,
})

const delegation: CreatePaperDelegationDto = {
toNationalId,
fromNationalId,
referenceId: 'ref1',
}

// Act
const res = await getRequestMethod(
server,
'POST',
)('/delegation-admin').send(delegation)

expect(res.status).toEqual(400)
})
})
})
Loading

0 comments on commit 8eb057b

Please sign in to comment.