From 4959514cbc0d7617e6e30a1c03a67cb708bc1825 Mon Sep 17 00:00:00 2001 From: kksteini <77672665+kksteini@users.noreply.github.com> Date: Wed, 29 May 2024 13:58:26 +0000 Subject: [PATCH 01/82] chore(application-marriage-conditions): Update payments (#14951) * chore(application-marriage-conditions): Update payments * Accidental let changed to const * Update libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update libs/application/templates/marriage-conditions/src/lib/utils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: nx format:write update dirty files * Update libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: andes-it --- .../{jest.config.js => jest.config.ts} | 3 +- .../marriage-conditions/project.json | 10 +++ .../src/dataProviders/index.ts | 14 +++- .../src/fields/PaymentInfo/index.tsx | 83 +++++++++++++++++-- .../src/forms/application.ts | 26 ++++-- .../forms/sharedSections/dataCollection.ts | 6 ++ .../src/lib/MarriageConditionsTemplate.ts | 8 +- .../marriage-conditions/src/lib/utils.spec.ts | 19 +++++ .../marriage-conditions/src/lib/utils.ts | 3 + 9 files changed, 159 insertions(+), 13 deletions(-) rename libs/application/templates/marriage-conditions/{jest.config.js => jest.config.ts} (91%) create mode 100644 libs/application/templates/marriage-conditions/src/lib/utils.spec.ts diff --git a/libs/application/templates/marriage-conditions/jest.config.js b/libs/application/templates/marriage-conditions/jest.config.ts similarity index 91% rename from libs/application/templates/marriage-conditions/jest.config.js rename to libs/application/templates/marriage-conditions/jest.config.ts index f171115544a5..9cf5dcb16255 100644 --- a/libs/application/templates/marriage-conditions/jest.config.js +++ b/libs/application/templates/marriage-conditions/jest.config.ts @@ -1,4 +1,5 @@ -module.exports = { +/* eslint-disable */ +export default { preset: './jest.preset.js', rootDir: '../../../..', roots: [__dirname], diff --git a/libs/application/templates/marriage-conditions/project.json b/libs/application/templates/marriage-conditions/project.json index c43264913c55..9f54467e8a3a 100644 --- a/libs/application/templates/marriage-conditions/project.json +++ b/libs/application/templates/marriage-conditions/project.json @@ -23,6 +23,16 @@ "options": { "command": "graphql-codegen --config libs/application/templates/marriage-conditions/codegen.yml" } + }, + "test": { + "executor": "@nx/jest:jest", + "options": { + "jestConfig": "libs/application/templates/marriage-conditions/jest.config.ts", + "passWithNoTests": true + }, + "outputs": [ + "{workspaceRoot}/coverage/libs/application/templates/marriage-conditions" + ] } }, "tags": ["scope:application-system", "lib:application-system"] diff --git a/libs/application/templates/marriage-conditions/src/dataProviders/index.ts b/libs/application/templates/marriage-conditions/src/dataProviders/index.ts index 5727b79366b7..9b13cb2ddffc 100644 --- a/libs/application/templates/marriage-conditions/src/dataProviders/index.ts +++ b/libs/application/templates/marriage-conditions/src/dataProviders/index.ts @@ -1,4 +1,8 @@ -import { defineTemplateApi } from '@island.is/application/types' +import { + InstitutionNationalIds, + PaymentCatalogApi, + defineTemplateApi, +} from '@island.is/application/types' export { NationalRegistryUserApi, @@ -14,3 +18,11 @@ export const ReligionCodesApi = defineTemplateApi({ action: 'religionCodes', externalDataId: 'religions', }) + +export const DistrictCommissionersPaymentCatalogApi = + PaymentCatalogApi.configure({ + params: { + organizationId: InstitutionNationalIds.SYSLUMENN, + }, + externalDataId: 'paymentDistrictCommissioners', + }) diff --git a/libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx b/libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx index a7b0b29bd0d5..be4a39707fac 100644 --- a/libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx +++ b/libs/application/templates/marriage-conditions/src/fields/PaymentInfo/index.tsx @@ -3,6 +3,7 @@ import { Box, Divider, Text } from '@island.is/island-ui/core' import { FieldBaseProps } from '@island.is/application/types' import { useLocale } from '@island.is/localization' import { m } from '../../lib/messages' +import { formatIsk } from '../../lib/utils' export type Individual = { name: string @@ -11,9 +12,75 @@ export type Individual = { email: string } -export const PaymentInfo: FC> = () => { +type Payment = { + chargeItemCode: string + priceAmount: number +} + +type FakeData = { + allowFakeData: boolean + fakePayments: Array +} + +type PaymentInfoProps = { + field: { + props: FakeData + } +} + +export const PaymentInfo: FC< + React.PropsWithChildren & PaymentInfoProps +> = ({ field, application }) => { const { formatMessage } = useLocale() + // Get Payment Catalog + const paymentCatalog = application.externalData?.paymentDistrictCommissioners + ?.data as Array + + // Get Charge Codes + let birthCertCode = paymentCatalog?.find( + (payment) => payment.chargeItemCode === 'AY153', + ) + let maritalCertCode = paymentCatalog?.find( + (payment) => payment.chargeItemCode === 'AY154', + ) + + const surveyCertCode = paymentCatalog?.find( + (payment) => payment.chargeItemCode === 'AY128', + ) + + const marriageConditionsCode = paymentCatalog?.find( + (payment) => payment.chargeItemCode === 'AY129', + ) + + // Fallback on fake data if on dev + // TODO: remove once paymentcatalog is updated on dev to reflect prod + if (field.props.allowFakeData) { + birthCertCode = field?.props?.fakePayments?.find( + (payment) => payment.chargeItemCode === 'AY153', + ) + maritalCertCode = field?.props?.fakePayments?.find( + (payment) => payment.chargeItemCode === 'AY154', + ) + } + + // Isolate prices, calculate total and check if total is correct + const prices = { + birthCertificate: 2 * (birthCertCode?.priceAmount ?? 0), + maritalCertificate: 2 * (maritalCertCode?.priceAmount ?? 0), + marriageConditions: marriageConditionsCode?.priceAmount ?? 0, + surveyCertificate: surveyCertCode?.priceAmount ?? 0, + } + + // If correctTotal is false we only display final price + // To avoid embarrassing mistakes on production if prices + // descynchronize + const correctTotal = + prices.birthCertificate + + prices.maritalCertificate + + prices.surveyCertificate === + prices.marriageConditions + return ( @@ -21,15 +88,21 @@ export const PaymentInfo: FC> = () => { {formatMessage(m.maritalStatusCertificates)} - 5.800 kr. + + {correctTotal ? formatIsk(prices.maritalCertificate) : ''} + {formatMessage(m.birthCertificates)} - 5.800 kr. + + {correctTotal ? formatIsk(prices.birthCertificate) : ''} + {formatMessage(m.surveyCertificate)} - 4.800 kr. + + {correctTotal ? formatIsk(prices.surveyCertificate) : ''} + @@ -37,7 +110,7 @@ export const PaymentInfo: FC> = () => { {formatMessage(m.total)} - 16.400 kr. + {formatIsk(prices.marriageConditions)} diff --git a/libs/application/templates/marriage-conditions/src/forms/application.ts b/libs/application/templates/marriage-conditions/src/forms/application.ts index 7587055e08f6..bb0f7e08ff38 100644 --- a/libs/application/templates/marriage-conditions/src/forms/application.ts +++ b/libs/application/templates/marriage-conditions/src/forms/application.ts @@ -459,11 +459,27 @@ export const getApplication = ({ allowFakeData = false }): Form => { id: 'payment', title: '', children: [ - buildCustomField({ - id: 'payment', - title: '', - component: 'PaymentInfo', - }), + buildCustomField( + { + id: 'payment', + title: '', + component: 'PaymentInfo', + }, + { + allowFakeData, + // TODO: When/if real data enters the payment catalog, remove this + fakePayments: [ + { + priceAmount: 2800, + chargeItemCode: 'AY153', + }, + { + priceAmount: 2700, + chargeItemCode: 'AY154', + }, + ], + }, + ), buildSubmitField({ id: 'submitPayment', title: '', diff --git a/libs/application/templates/marriage-conditions/src/forms/sharedSections/dataCollection.ts b/libs/application/templates/marriage-conditions/src/forms/sharedSections/dataCollection.ts index 1ab7b037a086..d04792950a94 100644 --- a/libs/application/templates/marriage-conditions/src/forms/sharedSections/dataCollection.ts +++ b/libs/application/templates/marriage-conditions/src/forms/sharedSections/dataCollection.ts @@ -5,6 +5,7 @@ import { NationalRegistryUserApi, UserProfileApi, ReligionCodesApi, + DistrictCommissionersPaymentCatalogApi, } from '../../dataProviders' import { m } from '../../lib/messages' @@ -33,4 +34,9 @@ export const dataCollection = [ title: '', subTitle: '', }), + buildDataProviderItem({ + provider: DistrictCommissionersPaymentCatalogApi, + title: '', + subTitle: '', + }), ] diff --git a/libs/application/templates/marriage-conditions/src/lib/MarriageConditionsTemplate.ts b/libs/application/templates/marriage-conditions/src/lib/MarriageConditionsTemplate.ts index f5d899778ef3..a5939d749794 100644 --- a/libs/application/templates/marriage-conditions/src/lib/MarriageConditionsTemplate.ts +++ b/libs/application/templates/marriage-conditions/src/lib/MarriageConditionsTemplate.ts @@ -23,7 +23,11 @@ import { getApplicationFeatureFlags, MarriageCondtionsFeatureFlags, } from './getApplicationFeatureFlags' -import { MaritalStatusApi, ReligionCodesApi } from '../dataProviders' +import { + DistrictCommissionersPaymentCatalogApi, + MaritalStatusApi, + ReligionCodesApi, +} from '../dataProviders' import { coreHistoryMessages } from '@island.is/application/core' import { buildPaymentState } from '@island.is/application/utils' @@ -82,6 +86,7 @@ const MarriageConditionsTemplate: ApplicationTemplate< DistrictsApi, MaritalStatusApi, ReligionCodesApi, + DistrictCommissionersPaymentCatalogApi, ], delete: true, }, @@ -148,6 +153,7 @@ const MarriageConditionsTemplate: ApplicationTemplate< DistrictsApi, MaritalStatusApi, ReligionCodesApi, + DistrictCommissionersPaymentCatalogApi, ], }, ], diff --git a/libs/application/templates/marriage-conditions/src/lib/utils.spec.ts b/libs/application/templates/marriage-conditions/src/lib/utils.spec.ts new file mode 100644 index 000000000000..b3600932e4e0 --- /dev/null +++ b/libs/application/templates/marriage-conditions/src/lib/utils.spec.ts @@ -0,0 +1,19 @@ +// Write tests for the utils functions +import { formatIsk } from './utils' + +describe('utils', () => { + describe('formatIsk', () => { + it('should format a number to Icelandic currency', () => { + expect(formatIsk(1)).toBe('1 kr.') + expect(formatIsk(22)).toBe('22 kr.') + expect(formatIsk(333)).toBe('333 kr.') + expect(formatIsk(4_444)).toBe('4.444 kr.') + expect(formatIsk(55_555)).toBe('55.555 kr.') + expect(formatIsk(666_666)).toBe('666.666 kr.') + expect(formatIsk(7_777_777)).toBe('7.777.777 kr.') + expect(formatIsk(88_888_888)).toBe('88.888.888 kr.') + expect(formatIsk(999_999_999)).toBe('999.999.999 kr.') + expect(formatIsk(1_010_101_010)).toBe('1.010.101.010 kr.') + }) + }) +}) diff --git a/libs/application/templates/marriage-conditions/src/lib/utils.ts b/libs/application/templates/marriage-conditions/src/lib/utils.ts index ccad28919a41..cac1639c3e74 100644 --- a/libs/application/templates/marriage-conditions/src/lib/utils.ts +++ b/libs/application/templates/marriage-conditions/src/lib/utils.ts @@ -13,3 +13,6 @@ export const getSpouseNationalId = (answers: FormValue): string => export const removeCountryCode = (phone: string) => { return phone.replace(/(^00354|^\+354|\D)/g, '') } + +export const formatIsk = (value: number): string => + `${value.toLocaleString('is-IS')} kr.` From 6109b7ca453a757fad343a241a651a692151e657 Mon Sep 17 00:00:00 2001 From: kksteini <77672665+kksteini@users.noreply.github.com> Date: Wed, 29 May 2024 14:11:24 +0000 Subject: [PATCH 02/82] feat(application-ir): Add casenumber to submit (#14919) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../modules/templates/inheritance-report/utils/mappers.ts | 6 +++++- .../templates/inheritance-report/src/lib/dataSchema.ts | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts index 27a275611ee8..60a03ade6192 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts @@ -88,7 +88,9 @@ export const estateTransformer = (estate: EstateInfo): InheritanceData => { export const expandAnswers = ( answers: InheritanceReportSchema, -): InheritanceReportSchema => { +): Omit & { + caseNumber: string +} => { return { applicant: answers.applicant, approveExternalData: answers.approveExternalData, @@ -205,6 +207,7 @@ export const expandAnswers = ( total: answers.assets.vehicles?.total ?? 0, }, }, + caseNumber: answers.estateInfoSelection, confirmAction: answers.confirmAction, debts: { debtsTotal: answers.debts.debtsTotal ?? 0, @@ -223,6 +226,7 @@ export const expandAnswers = ( }, publicCharges: (answers.debts.publicCharges ?? 0).toString(), }, + estateInfoSelection: answers.estateInfoSelection, funeralCost: { build: answers?.funeralCost?.build ?? '', cremation: answers?.funeralCost?.cremation ?? '', diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index 60128a998ceb..cf117d2a58ec 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -377,6 +377,8 @@ export const inheritanceReportSchema = z.object({ debtsTotal: z.number().optional(), }), + estateInfoSelection: z.string().min(1), + funeralCost: z .object({ build: z.string().optional(), From 3e110b11116bdf826e4533352b11cfa67424e9fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Wed, 29 May 2024 15:07:49 +0000 Subject: [PATCH 03/82] feat(j-s): Store MD5 Sum for Confirmed Indictments (#14842) * Sets indictment denied explanation to null rather than the empty string when a case is submitted * Moves INDICTMENT_CONFIRMED event log to the case service to guarantee that it succeeds if and only if the SUBMIT transition succeeds. * Tries to upload generated case files record for submitted cases in the pdf service * Rewrites case files record uploads to police and court * Rewrites is traffic violation case checks * Rewrites get indictment pdf * Delivers traffic violation indictment to court * Removes unnecessary db call to get event logs * Rewrites getting generated files from s3 * Rewrites put object * Rewrites aws s3 methods * Confirmes indictments when getting signed urls * Confirms indictments on delivery to court and court of appeals * Confirms indictments on upload to police * Fixes time to live handling * Deletes confirmed indictments * Archives confirmed indctments * Removes comment * Adds TODO * Removes unused imports * Stores md5 has for indictment files * Removes console.log * Fixes key handling when uploading to s3 * Clears indictment hash when indictment is returned from court * Only gets confirmed indictment from s3 if indictment hash is null * Updates unit tests * Regenerates confirmed indictments on resend * Rearranges code --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../api/src/app/modules/auth/auth.service.ts | 2 +- .../file/models/presignedPost.model.ts | 3 + .../20240522092213-update-file-keys.js | 67 +++ .../app/formatters/confirmedIndictmentPdf.ts | 2 +- .../src/app/formatters/formatters.spec.ts | 1 + .../backend/src/app/formatters/index.ts | 3 +- .../src/app/formatters/indictmentPdf.ts | 12 +- .../backend/src/app/messages/courtUpload.ts | 5 + .../src/app/modules/aws-s3/awsS3.service.ts | 404 +++++++++++++++-- .../src/app/modules/case/case.controller.ts | 15 +- .../src/app/modules/case/case.service.ts | 95 +++- .../app/modules/case/filters/cases.filter.ts | 1 - .../interceptors/transition.interceptor.ts | 92 ---- .../modules/case/internalCase.controller.ts | 21 + .../app/modules/case/internalCase.service.ts | 418 +++++++----------- .../modules/case/limitedAccessCase.service.ts | 3 +- .../src/app/modules/case/models/case.model.ts | 8 + .../src/app/modules/case/pdf.service.ts | 162 ++++--- .../case/test/caseController/getAll.spec.ts | 2 +- .../getCaseFilesRecordPdf.spec.ts | 48 +- .../caseController/getCourtRecordPdf.spec.ts | 29 +- ...etCourtRecordSignatureConfirmation.spec.ts | 23 +- .../caseController/getIndictmentPdf.spec.ts | 44 +- .../test/caseController/getRulingPdf.spec.ts | 105 ++--- .../getRulingSignatureConfirmation.spec.ts | 23 +- .../test/caseController/transition.spec.ts | 12 +- .../case/test/caseController/update.spec.ts | 1 + .../archiveCaseFilesRecord.spec.ts | 34 +- .../deliverAppealToPolice.spec.ts | 18 +- .../deliverCaseFilesRecordToCourt.spec.ts | 68 +-- ...eliverCaseFilesRecordToCourtGuards.spec.ts | 34 +- .../deliverCaseFilesRecordToPolice.spec.ts | 57 +-- .../deliverCaseToPolice.spec.ts | 8 +- .../deliverIndictmentCaseToPolice.spec.ts | 18 +- .../deliverIndictmentToCourt.spec.ts | 166 +++++++ .../deliverIndictmentToCourtGuards.spec.ts | 26 ++ .../deliverIndictmentToPolice.spec.ts | 93 +++- .../deliverIndictmentToPoliceGuards.spec.ts | 34 +- .../deliverSignedRulingToCourt.spec.ts | 41 +- .../deliverSignedRulingToPolice.spec.ts | 18 +- .../getCaseFilesRecordPdf.spec.ts | 48 +- .../getCourtRecordPdf.spec.ts | 84 ++-- .../getIndictmentPdf.spec.ts | 43 +- .../getRulingPdf.spec.ts | 79 ++-- .../app/modules/event-log/eventLog.service.ts | 37 +- .../src/app/modules/file/file.controller.ts | 5 +- .../src/app/modules/file/file.module.ts | 3 +- .../src/app/modules/file/file.service.ts | 283 ++++++------ .../modules/file/internalFile.controller.ts | 4 +- .../file/limitedAccessFile.controller.ts | 3 +- .../src/app/modules/file/models/file.model.ts | 4 + .../file/models/presignedPost.model.ts | 3 + .../fileController/createCaseFile.spec.ts | 18 +- .../createPresignedPost.spec.ts | 39 +- .../fileController/deleteCaseFile.spec.ts | 76 ++-- .../getCaseFileSignedUrl.spec.ts | 118 ++--- .../uploadCaseFileToCourt.spec.ts | 59 +-- .../archiveCaseFile.spec.ts | 40 +- .../deliverCaseFileToCourt.spec.ts | 38 +- .../deliverCaseFileToCourtOfAppeals.spec.ts | 10 +- .../createCaseFile.spec.ts | 18 +- .../createPresignedPost.spec.ts | 35 +- .../deleteCaseFile.spec.ts | 78 ++-- .../getCaseFileSignedUrl.spec.ts | 50 ++- .../modules/institution/test/getAll.spec.ts | 2 +- .../backend/src/app/modules/police/index.ts | 6 +- .../app/modules/police/police.controller.ts | 1 + .../src/app/modules/police/police.service.ts | 24 +- .../police/test/updatePoliceCase.spec.ts | 6 +- .../police/test/uploadPoliceCaseFile.spec.ts | 133 ++++-- .../src/app/modules/user/test/create.spec.ts | 2 +- .../src/app/modules/user/test/getAll.spec.ts | 4 +- .../src/app/modules/user/test/getById.spec.ts | 2 +- .../modules/user/test/getByNationalId.spec.ts | 2 +- .../src/app/modules/user/test/update.spec.ts | 4 +- .../IndictmentCaseFilesList.tsx | 8 +- .../CaseOverviewHeader/CaseOverviewHeader.tsx | 4 +- .../Indictments/CaseFiles/CaseFiles.tsx | 4 +- .../Indictments/Processing/Processing.tsx | 4 +- .../web/src/utils/hooks/useCaseList/index.tsx | 4 +- .../useS3Upload/createPresignedPost.graphql | 1 + .../limitedAccessCreatePresignedPost.graphql | 1 + .../utils/hooks/useS3Upload/useS3Upload.ts | 6 +- .../web/src/utils/hooks/useSections/index.ts | 8 +- .../web/src/utils/stepHelper.ts | 20 - .../judicial-system/web/src/utils/validate.ts | 5 +- .../message/src/lib/message.ts | 3 + libs/judicial-system/types/src/index.ts | 2 +- libs/judicial-system/types/src/lib/case.ts | 48 +- 89 files changed, 2113 insertions(+), 1582 deletions(-) create mode 100644 apps/judicial-system/backend/migrations/20240522092213-update-file-keys.js delete mode 100644 apps/judicial-system/backend/src/app/modules/case/interceptors/transition.interceptor.ts create mode 100644 apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourt.spec.ts create mode 100644 apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourtGuards.spec.ts diff --git a/apps/judicial-system/api/src/app/modules/auth/auth.service.ts b/apps/judicial-system/api/src/app/modules/auth/auth.service.ts index 47dfeaf72b17..9f2ea5e7b278 100644 --- a/apps/judicial-system/api/src/app/modules/auth/auth.service.ts +++ b/apps/judicial-system/api/src/app/modules/auth/auth.service.ts @@ -160,7 +160,7 @@ export class AuthService { nationalId: string } } catch (error) { - console.error('Token verification failed:', error) + this.logger.error('Token verification failed:', error) throw error } } diff --git a/apps/judicial-system/api/src/app/modules/file/models/presignedPost.model.ts b/apps/judicial-system/api/src/app/modules/file/models/presignedPost.model.ts index b9bbc73f354e..c2d419bdee0e 100644 --- a/apps/judicial-system/api/src/app/modules/file/models/presignedPost.model.ts +++ b/apps/judicial-system/api/src/app/modules/file/models/presignedPost.model.ts @@ -9,4 +9,7 @@ export class PresignedPost { @Field(() => graphqlTypeJson) readonly fields!: { [key: string]: string } + + @Field(() => String) + readonly key!: string } diff --git a/apps/judicial-system/backend/migrations/20240522092213-update-file-keys.js b/apps/judicial-system/backend/migrations/20240522092213-update-file-keys.js new file mode 100644 index 000000000000..49b35862d68a --- /dev/null +++ b/apps/judicial-system/backend/migrations/20240522092213-update-file-keys.js @@ -0,0 +1,67 @@ +'use strict' + +module.exports = { + async up(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((transaction) => + Promise.all([ + queryInterface.sequelize.query( + `UPDATE case_file + SET key = SUBSTRING(key FROM 9) + WHERE key LIKE 'uploads/' || '%'; + UPDATE case_file + SET key = SUBSTRING(key FROM 23) + WHERE key LIKE 'indictments/completed/' || '%'; + UPDATE case_file + SET key = SUBSTRING(key FROM 13) + WHERE key LIKE 'indictments/' || '%';`, + { transaction }, + ), + queryInterface.addColumn( + 'case', + 'indictment_hash', + { type: Sequelize.STRING, allowNull: true }, + { transaction }, + ), + queryInterface.addColumn( + 'case_file', + 'hash', + { type: Sequelize.STRING, allowNull: true }, + { transaction }, + ), + ]), + ) + }, + + async down(queryInterface) { + return queryInterface.sequelize.transaction((transaction) => + Promise.all([ + queryInterface.sequelize.query( + `UPDATE case_file + SET key = 'uploads/' || key + WHERE key IS NOT NULL AND case_id IN ( + SELECT id + FROM "case" + WHERE type != 'INDICTMENT' + ); + UPDATE case_file + SET key = 'indictments/completed/' || key + WHERE key IS NOT NULL AND case_id IN ( + SELECT id + FROM "case" + WHERE type = 'INDICTMENT' AND state = 'COMPLETED' + ); + UPDATE case_file + SET key = 'indictments/' || key + WHERE key IS NOT NULL AND case_id IN ( + SELECT id + FROM "case" + WHERE type = 'INDICTMENT' AND state != 'COMPLETED' + );`, + { transaction }, + ), + queryInterface.removeColumn('case', 'indictment_hash', { transaction }), + queryInterface.removeColumn('case_file', 'hash', { transaction }), + ]), + ) + }, +} diff --git a/apps/judicial-system/backend/src/app/formatters/confirmedIndictmentPdf.ts b/apps/judicial-system/backend/src/app/formatters/confirmedIndictmentPdf.ts index 2f896a54141a..341797e8cfea 100644 --- a/apps/judicial-system/backend/src/app/formatters/confirmedIndictmentPdf.ts +++ b/apps/judicial-system/backend/src/app/formatters/confirmedIndictmentPdf.ts @@ -2,8 +2,8 @@ import { applyCase } from 'beygla' import { PDFDocument, rgb, StandardFonts } from 'pdf-lib' import { formatDate } from '@island.is/judicial-system/formatters' -import { IndictmentConfirmation } from '@island.is/judicial-system/types' +import { IndictmentConfirmation } from './indictmentPdf' import { drawTextWithEllipsisPDFKit } from './pdfHelpers' import { PDFKitCoatOfArms } from './PDFKitCoatOfArms' diff --git a/apps/judicial-system/backend/src/app/formatters/formatters.spec.ts b/apps/judicial-system/backend/src/app/formatters/formatters.spec.ts index 31042ac3dba0..1e481e244591 100644 --- a/apps/judicial-system/backend/src/app/formatters/formatters.spec.ts +++ b/apps/judicial-system/backend/src/app/formatters/formatters.spec.ts @@ -46,6 +46,7 @@ export const makeProsecutor = (): User => { role: UserRole.PROSECUTOR, active: true, title: 'aðstoðarsaksóknari', + canConfirmIndictment: true, institution: { id: '', created: '', diff --git a/apps/judicial-system/backend/src/app/formatters/index.ts b/apps/judicial-system/backend/src/app/formatters/index.ts index b69fe76741ef..3807e29bbac5 100644 --- a/apps/judicial-system/backend/src/app/formatters/index.ts +++ b/apps/judicial-system/backend/src/app/formatters/index.ts @@ -32,4 +32,5 @@ export { export { getRequestPdfAsBuffer, getRequestPdfAsString } from './requestPdf' export { getRulingPdfAsBuffer, getRulingPdfAsString } from './rulingPdf' export { createCaseFilesRecord } from './caseFilesRecordPdf' -export { createIndictment } from './indictmentPdf' +export { createIndictment, IndictmentConfirmation } from './indictmentPdf' +export { createConfirmedIndictment } from './confirmedIndictmentPdf' diff --git a/apps/judicial-system/backend/src/app/formatters/indictmentPdf.ts b/apps/judicial-system/backend/src/app/formatters/indictmentPdf.ts index 750b82bd7ce0..19716636f770 100644 --- a/apps/judicial-system/backend/src/app/formatters/indictmentPdf.ts +++ b/apps/judicial-system/backend/src/app/formatters/indictmentPdf.ts @@ -8,10 +8,6 @@ import { formatDate, lowercase, } from '@island.is/judicial-system/formatters' -import { - CaseState, - type IndictmentConfirmation, -} from '@island.is/judicial-system/types' import { nowFactory } from '../factories' import { indictment } from '../messages' @@ -56,6 +52,12 @@ const roman = (num: number) => { return str } +export interface IndictmentConfirmation { + actor: string + institution: string + date: Date +} + export const createIndictment = async ( theCase: Case, formatMessage: FormatMessage, @@ -81,7 +83,7 @@ export const createIndictment = async ( setTitle(doc, title) - if (theCase.state === CaseState.SUBMITTED && confirmation) { + if (confirmation) { addIndictmentConfirmation( doc, confirmation.actor, diff --git a/apps/judicial-system/backend/src/app/messages/courtUpload.ts b/apps/judicial-system/backend/src/app/messages/courtUpload.ts index c14ed09b7836..060c9cd8cb05 100644 --- a/apps/judicial-system/backend/src/app/messages/courtUpload.ts +++ b/apps/judicial-system/backend/src/app/messages/courtUpload.ts @@ -6,6 +6,11 @@ export const courtUpload = defineMessages({ defaultMessage: 'Krafa um {caseType} {date}', description: 'Notaður sem nafn á kröfuskjali í Auði.', }, + indictment: { + id: 'judicial.system.backend:court_upload.indictment', + defaultMessage: 'Ákæra', + description: 'Notaður sem nafn á ákæru í Auði.', + }, caseFilesRecord: { id: 'judicial.system.backend:court_upload.case_files_record', defaultMessage: 'Skjalaskrá {policeCaseNumber}', diff --git a/apps/judicial-system/backend/src/app/modules/aws-s3/awsS3.service.ts b/apps/judicial-system/backend/src/app/modules/aws-s3/awsS3.service.ts index 3ffe4f13c044..1b781380af3b 100644 --- a/apps/judicial-system/backend/src/app/modules/aws-s3/awsS3.service.ts +++ b/apps/judicial-system/backend/src/app/modules/aws-s3/awsS3.service.ts @@ -2,10 +2,36 @@ import { S3 } from 'aws-sdk' import { Inject, Injectable } from '@nestjs/common' +import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import type { ConfigType } from '@island.is/nest/config' +import { + CaseState, + CaseType, + isCompletedCase, + isIndictmentCase, +} from '@island.is/judicial-system/types' + import { awsS3ModuleConfig } from './awsS3.config' +const requestPrefix = 'uploads/' +const generatedPrefix = 'generated/' +const indictmentPrefix = 'indictments/' +const completedIndictmentPrefix = 'indictments/completed/' + +const formatConfirmedKey = (key: string) => + key.replace(/\/([^/]*)$/, '/confirmed/$1') +const formatS3RequestKey = (key: string) => `${requestPrefix}${key}` +const formatS3IndictmentKey = (key: string) => `${indictmentPrefix}${key}` +const formatS3CompletedIndictmentKey = (key: string) => + `${completedIndictmentPrefix}${key}` +const formatS3Key = (caseType: CaseType, caseState: CaseState, key: string) => + isIndictmentCase(caseType) + ? isCompletedCase(caseState) + ? formatS3CompletedIndictmentKey(key) + : formatS3IndictmentKey(key) + : formatS3RequestKey(key) + @Injectable() export class AwsS3Service { private readonly s3: S3 @@ -13,18 +39,24 @@ export class AwsS3Service { constructor( @Inject(awsS3ModuleConfig.KEY) private readonly config: ConfigType, + @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) { this.s3 = new S3({ region: this.config.region }) } - createPresignedPost(key: string, type: string): Promise { + createPresignedPost( + caseType: CaseType, + caseState: CaseState, + key: string, + type: string, + ): Promise { return new Promise((resolve, reject) => { this.s3.createPresignedPost( { Bucket: this.config.bucket, Expires: this.config.timeToLivePost, Fields: { - key, + key: formatS3Key(caseType, caseState, key), 'content-type': type, 'Content-Disposition': 'inline', }, @@ -40,7 +72,56 @@ export class AwsS3Service { }) } - getSignedUrl(key: string, timeToLive?: number): Promise { + private objectExistsInS3(key: string): Promise { + return this.s3 + .headObject({ + Bucket: this.config.bucket, + Key: key, + }) + .promise() + .then( + () => true, + () => { + // The error is either 404 Not Found or 403 Forbidden. + // Normally, we would check if the error is 404 Not Found. + // However, to avoid granting the service ListBucket permissions, + // we also allow 403 Forbidden. + return false + }, + ) + } + + private requestObjectExists(key: string): Promise { + return this.objectExistsInS3(formatS3RequestKey(key)) + } + + private async indictmentObjectExists( + caseSate: CaseState, + key: string, + ): Promise { + if (isCompletedCase(caseSate)) { + if (await this.objectExistsInS3(formatS3CompletedIndictmentKey(key))) { + return true + } + } + + return this.objectExistsInS3(formatS3IndictmentKey(key)) + } + + objectExists( + caseType: CaseType, + caseState: CaseState, + key: string, + ): Promise { + return isIndictmentCase(caseType) + ? this.indictmentObjectExists(caseState, key) + : this.requestObjectExists(key) + } + + private getSignedUrlFromS3( + key: string, + timeToLive?: number, + ): Promise { return new Promise((resolve, reject) => { this.s3.getSignedUrl( 'getObject', @@ -60,36 +141,89 @@ export class AwsS3Service { }) } - async deleteObject(key: string): Promise { - return this.s3 - .deleteObject({ - Bucket: this.config.bucket, - Key: key, - }) - .promise() - .then(() => true) + private getRequestSignedUrl( + key: string, + timeToLive?: number, + ): Promise { + return this.getSignedUrlFromS3(formatS3RequestKey(key), timeToLive) } - objectExists(key: string): Promise { - return this.s3 - .headObject({ - Bucket: this.config.bucket, - Key: key, - }) - .promise() - .then( - () => true, - () => { - // The error is either 404 Not Found or 403 Forbidden. - // Normally, we would check if the error is 404 Not Found. - // However, to avoid granting the service ListBucket permissions, - // we also allow 403 Forbidden. - return false - }, - ) + private async getIndictmentSignedUrl( + caseSate: CaseState, + key: string, + timeToLive?: number, + ): Promise { + if (isCompletedCase(caseSate)) { + const completedKey = formatS3CompletedIndictmentKey(key) + + if (await this.objectExistsInS3(completedKey)) { + return await this.getSignedUrlFromS3(completedKey, timeToLive) + } + } + + return this.getSignedUrlFromS3(formatS3IndictmentKey(key), timeToLive) + } + + getSignedUrl( + caseType: CaseType, + caseState: CaseState, + key?: string, + timeToLive?: number, + ): Promise { + if (!key) { + throw new Error('Key is required') + } + + return isIndictmentCase(caseType) + ? this.getIndictmentSignedUrl(caseState, key, timeToLive) + : this.getRequestSignedUrl(key, timeToLive) } - async getObject(key: string): Promise { + async getConfirmedSignedUrl( + caseType: CaseType, + caseState: CaseState, + key: string | undefined, + force: boolean, + confirmContent: (content: Buffer) => Promise, + timeToLive?: number, + ): Promise { + if (!key) { + throw new Error('Key is required') + } + + if (!isIndictmentCase(caseType)) { + throw new Error('Only indictment case objects can be confirmed') + } + + const confirmedKey = formatConfirmedKey(key) + + if ( + !force && + (await this.indictmentObjectExists(caseState, confirmedKey)) + ) { + return this.getIndictmentSignedUrl(caseState, confirmedKey, timeToLive) + } + + const confirmedContent = await this.getIndictmentObject( + caseState, + key, + ).then((content) => confirmContent(content)) + + if (!confirmedContent) { + return this.getIndictmentSignedUrl(caseState, key, timeToLive) + } + + return this.putConfirmedObject( + caseType, + caseState, + key, + confirmedContent, + ).then(() => + this.getIndictmentSignedUrl(caseState, confirmedKey, timeToLive), + ) + } + + private async getObjectFromS3(key: string): Promise { return this.s3 .getObject({ Bucket: this.config.bucket, @@ -99,7 +233,88 @@ export class AwsS3Service { .then((data) => data.Body as Buffer) } - async putObject(key: string, content: string): Promise { + private getRequestObject(key: string): Promise { + return this.getObjectFromS3(formatS3RequestKey(key)) + } + + private async getIndictmentObject( + caseSate: CaseState, + key: string, + ): Promise { + if (isCompletedCase(caseSate)) { + const completedKey = formatS3CompletedIndictmentKey(key) + + if (await this.objectExistsInS3(completedKey)) { + return await this.getObjectFromS3(completedKey) + } + } + + return this.getObjectFromS3(formatS3IndictmentKey(key)) + } + + async getObject( + caseType: CaseType, + caseState: CaseState, + key?: string, + ): Promise { + if (!key) { + throw new Error('Key is required') + } + + return isIndictmentCase(caseType) + ? this.getIndictmentObject(caseState, key) + : this.getRequestObject(key) + } + + getGeneratedObject(caseType: CaseType, key: string): Promise { + if (isIndictmentCase(caseType)) { + throw new Error('Only request case objects can be generated') + } + + return this.getObjectFromS3(`${generatedPrefix}${key}`) + } + + async getConfirmedObject( + caseType: CaseType, + caseState: CaseState, + key: string | undefined, + force: boolean, + confirmContent: (content: Buffer) => Promise, + ): Promise { + if (!key) { + throw new Error('Key is required') + } + + if (!isIndictmentCase(caseType)) { + throw new Error('Only indictment case objects can be confirmed') + } + + const confirmedKey = formatConfirmedKey(key) + + if ( + !force && + (await this.indictmentObjectExists(caseState, confirmedKey)) + ) { + return this.getIndictmentObject(caseState, confirmedKey) + } + + const content = await this.getIndictmentObject(caseState, key) + + const confirmedContent = await confirmContent(content) + + if (!confirmedContent) { + return this.getIndictmentObject(caseState, key) + } + + return this.putConfirmedObject( + caseType, + caseState, + key, + confirmedContent, + ).then(() => this.getIndictmentObject(caseState, confirmedKey)) + } + + private async putObjectToS3(key: string, content: string): Promise { return this.s3 .putObject({ Bucket: this.config.bucket, @@ -111,7 +326,95 @@ export class AwsS3Service { .then(() => key) } - async copyObject(key: string, newKey: string): Promise { + async putObject( + caseType: CaseType, + caseState: CaseState, + key: string, + content: string, + ): Promise { + return this.putObjectToS3(formatS3Key(caseType, caseState, key), content) + } + + putGeneratedObject( + caseType: CaseType, + key: string, + content: string, + ): Promise { + if (isIndictmentCase(caseType)) { + throw new Error('Only request case objects can be generated') + } + + return this.putObjectToS3(`${generatedPrefix}${key}`, content) + } + + putConfirmedObject( + caseType: CaseType, + caseState: CaseState, + key: string, + content: string, + ): Promise { + if (!isIndictmentCase(caseType)) { + throw new Error('Only indictment case objects can be confirmed') + } + + return this.putObject(caseType, caseState, formatConfirmedKey(key), content) + } + + private async deleteObjectFromS3(key: string): Promise { + return this.s3 + .deleteObject({ + Bucket: this.config.bucket, + Key: key, + }) + .promise() + .then(() => true) + .catch((reason) => { + // Tolerate failure, but log error + this.logger.error(`Failed to delete object ${key} from AWS S3`, { + reason, + }) + return false + }) + } + + private deleteRequestObject(key: string): Promise { + return this.deleteObjectFromS3(formatS3RequestKey(key)) + } + + private async deleteIndictmentObject( + caseSate: CaseState, + key: string, + ): Promise { + if (isCompletedCase(caseSate)) { + const completedKey = formatS3CompletedIndictmentKey(key) + + if (await this.objectExistsInS3(completedKey)) { + // No need to wait for the delete to finish + this.deleteObjectFromS3(formatConfirmedKey(completedKey)) + + return await this.deleteObjectFromS3(completedKey) + } + } + + const originalKey = formatS3IndictmentKey(key) + + // No need to wait for the delete to finish + this.deleteObjectFromS3(formatConfirmedKey(originalKey)) + + return this.deleteObjectFromS3(originalKey) + } + + async deleteObject( + caseType: CaseType, + caseState: CaseState, + key: string, + ): Promise { + return isIndictmentCase(caseType) + ? this.deleteIndictmentObject(caseState, key) + : this.deleteRequestObject(key) + } + + private async copyObject(key: string, newKey: string): Promise { return this.s3 .copyObject({ Bucket: this.config.bucket, @@ -121,4 +424,43 @@ export class AwsS3Service { .promise() .then(() => newKey) } + + async archiveObject( + caseType: CaseType, + caseState: CaseState, + key: string, + ): Promise { + if (!isIndictmentCase(caseType)) { + throw new Error('Only indictment case objects can be archived') + } + + if (!isCompletedCase(caseState)) { + throw new Error('Only completed indictment case objects can be archived') + } + + const oldKey = formatS3IndictmentKey(key) + const newKey = formatS3CompletedIndictmentKey(key) + + const oldConfirmedKey = formatConfirmedKey(oldKey) + + if (await this.objectExistsInS3(oldConfirmedKey)) { + const newConfirmedKey = formatConfirmedKey(newKey) + + if (!(await this.objectExistsInS3(newConfirmedKey))) { + await this.copyObject(oldConfirmedKey, newConfirmedKey) + } + + // No need to wait for the delete to finish + this.deleteObjectFromS3(oldConfirmedKey) + } + + if (!(await this.objectExistsInS3(newKey))) { + await this.copyObject(oldKey, newKey) + } + + // No need to wait for the delete to finish + this.deleteObjectFromS3(oldKey) + + return newKey + } } 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 a06ffadef641..d055e66339fb 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 @@ -96,7 +96,6 @@ import { } from './guards/rolesRules' import { CaseInterceptor } from './interceptors/case.interceptor' import { CaseListInterceptor } from './interceptors/caseList.interceptor' -import { TransitionInterceptor } from './interceptors/transition.interceptor' import { Case } from './models/case.model' import { SignatureConfirmationResponse } from './models/signatureConfirmation.response' import { transitionCase } from './state/case.state' @@ -260,7 +259,6 @@ export class CaseController { } @UseGuards(JwtAuthGuard, CaseExistsGuard, RolesGuard, CaseWriteGuard) - @UseInterceptors(TransitionInterceptor) @RolesRules( prosecutorTransitionRule, prosecutorRepresentativeTransitionRule, @@ -304,9 +302,8 @@ export class CaseController { `User ${user.id} does not have permission to confirm indictments`, ) } - if (theCase.indictmentDeniedExplanation) { - update.indictmentDeniedExplanation = '' - } + + update.indictmentDeniedExplanation = null } break case CaseTransition.ACCEPT: @@ -339,7 +336,6 @@ export class CaseController { ), } } - break case CaseTransition.REOPEN: update.rulingDate = null @@ -399,12 +395,11 @@ export class CaseController { } break case CaseTransition.ASK_FOR_CONFIRMATION: - if (theCase.indictmentReturnedExplanation) { - update.indictmentReturnedExplanation = '' - } + update.indictmentReturnedExplanation = null break case CaseTransition.RETURN_INDICTMENT: - update.courtCaseNumber = '' + update.courtCaseNumber = null + update.indictmentHash = null break case CaseTransition.REDISTRIBUTE: update.judgeId = null diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index e01cb4ae6e1e..36465195d58d 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -41,6 +41,7 @@ import { isCompletedCase, isIndictmentCase, isRestrictionCase, + isTrafficViolationCase, NotificationType, prosecutorCanSelectDefenderForInvestigationCase, UserRole, @@ -55,7 +56,7 @@ import { AwsS3Service } from '../aws-s3' import { CourtService } from '../court' import { Defendant, DefendantService } from '../defendant' import { CaseEvent, EventService } from '../event' -import { EventLog } from '../event-log' +import { EventLog, EventLogService } from '../event-log' import { CaseFile, FileService } from '../file' import { IndictmentCount } from '../indictment-count' import { Institution } from '../institution' @@ -104,7 +105,6 @@ export interface UpdateCase | 'caseFilesComments' | 'prosecutorId' | 'sharedWithProsecutorsOfficeId' - | 'courtCaseNumber' | 'sessionArrangements' | 'courtLocation' | 'courtStartDate' @@ -153,8 +153,6 @@ export interface UpdateCase | 'appealValidToDate' | 'isAppealCustodyIsolation' | 'appealIsolationToDate' - | 'indictmentDeniedExplanation' - | 'indictmentReturnedExplanation' | 'indictmentRulingDecision' | 'indictmentReviewerId' > { @@ -164,6 +162,7 @@ export interface UpdateCase defendantWaivesRightToCounsel?: boolean rulingDate?: Date | null rulingSignatureDate?: Date | null + courtCaseNumber?: string | null courtRecordSignatoryId?: string | null courtRecordSignatureDate?: Date | null parentCaseId?: string | null @@ -171,6 +170,9 @@ export interface UpdateCase courtDate?: UpdateDateLog | null postponedIndefinitelyExplanation?: string | null judgeId?: string | null + indictmentReturnedExplanation?: string | null + indictmentDeniedExplanation?: string | null + indictmentHash?: string | null } type DateLogKeys = keyof Pick @@ -271,6 +273,7 @@ export const include: Includeable[] = [ as: 'eventLogs', required: false, where: { eventType: { [Op.in]: eventTypes } }, + order: [['created', 'ASC']], separate: true, }, { @@ -364,6 +367,7 @@ export class CaseService { private readonly signingService: SigningService, private readonly intlService: IntlService, private readonly eventService: EventService, + private readonly eventLogService: EventLogService, private readonly messageService: MessageService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -388,7 +392,7 @@ export class CaseService { pdf: string, ): Promise { return this.awsS3Service - .putObject(`generated/${theCase.id}/ruling.pdf`, pdf) + .putGeneratedObject(theCase.type, `${theCase.id}/ruling.pdf`, pdf) .then(() => true) .catch((reason) => { this.logger.error( @@ -405,7 +409,7 @@ export class CaseService { pdf: string, ): Promise { return this.awsS3Service - .putObject(`generated/${theCase.id}/courtRecord.pdf`, pdf) + .putGeneratedObject(theCase.type, `${theCase.id}/courtRecord.pdf`, pdf) .then(() => true) .catch((reason) => { this.logger.error( @@ -465,7 +469,11 @@ export class CaseService { ) { for (const caseFile of theCase.caseFiles) { if (caseFile.policeCaseNumber === oldPoliceCaseNumbers[i]) { - await this.fileService.deleteCaseFile(caseFile, transaction) + await this.fileService.deleteCaseFile( + theCase, + caseFile, + transaction, + ) } } @@ -642,6 +650,19 @@ export class CaseService { elementId: policeCaseNumber, })) + const caseFilesCategories = isTrafficViolationCase(theCase) + ? [ + CaseFileCategory.COVER_LETTER, + CaseFileCategory.CRIMINAL_RECORD, + CaseFileCategory.COST_BREAKDOWN, + ] + : [ + CaseFileCategory.COVER_LETTER, + CaseFileCategory.INDICTMENT, + CaseFileCategory.CRIMINAL_RECORD, + CaseFileCategory.COST_BREAKDOWN, + ] + const deliverCaseFileToCourtMessages = theCase.caseFiles ?.filter( @@ -649,12 +670,7 @@ export class CaseService { caseFile.state === CaseFileState.STORED_IN_RVG && caseFile.key && ((caseFile.category && - [ - CaseFileCategory.COVER_LETTER, - CaseFileCategory.INDICTMENT, - CaseFileCategory.CRIMINAL_RECORD, - CaseFileCategory.COST_BREAKDOWN, - ].includes(caseFile.category)) || + caseFilesCategories.includes(caseFile.category)) || (caseFile.category === CaseFileCategory.CASE_FILE && !caseFile.policeCaseNumber)), ) @@ -665,12 +681,20 @@ export class CaseService { elementId: caseFile.id, })) ?? [] - return this.messageService.sendMessagesToQueue( - this.getDeliverProsecutorToCourtMessages(theCase, user) - .concat(this.getDeliverDefendantToCourtMessages(theCase, user)) - .concat(deliverCaseFilesRecordToCourtMessages) - .concat(deliverCaseFileToCourtMessages), - ) + const messages = this.getDeliverProsecutorToCourtMessages(theCase, user) + .concat(this.getDeliverDefendantToCourtMessages(theCase, user)) + .concat(deliverCaseFilesRecordToCourtMessages) + .concat(deliverCaseFileToCourtMessages) + + if (isTrafficViolationCase(theCase)) { + messages.push({ + type: MessageType.DELIVERY_TO_COURT_INDICTMENT, + user, + caseId: theCase.id, + }) + } + + return this.messageService.sendMessagesToQueue(messages) } private addMessagesForDefenderEmailChangeToQueue( @@ -1343,6 +1367,29 @@ export class CaseService { } } + handleEventLogs( + theCase: Case, + update: UpdateCase, + user: TUser, + transaction: Transaction, + ) { + if ( + isIndictmentCase(theCase.type) && + update.state === CaseState.SUBMITTED && + theCase.state === CaseState.WAITING_FOR_CONFIRMATION + ) { + return this.eventLogService.create( + { + eventType: EventType.INDICTMENT_CONFIRMED, + caseId: theCase.id, + nationalId: user.nationalId, + userRole: user.role, + }, + transaction, + ) + } + } + async update( theCase: Case, update: UpdateCase, @@ -1351,6 +1398,8 @@ export class CaseService { ): Promise { const receivingCase = update.courtCaseNumber && theCase.state === CaseState.SUBMITTED + const returningIndictmentCase = + update.state === CaseState.DRAFT && theCase.state === CaseState.RECEIVED return this.sequelize .transaction(async (transaction) => { @@ -1365,6 +1414,7 @@ export class CaseService { await this.handleDateUpdates(theCase, update, transaction) await this.handleCommentUpdates(theCase, update, transaction) + await this.handleEventLogs(theCase, update, user, transaction) if (Object.keys(update).length === 0) { return @@ -1401,6 +1451,13 @@ export class CaseService { ) { await this.fileService.resetCaseFileStates(theCase.id, transaction) } + + if (returningIndictmentCase) { + await this.fileService.resetIndictmentCaseFileHashes( + theCase.id, + transaction, + ) + } }) .then(async () => { const updatedCase = await this.findById(theCase.id, true) diff --git a/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts b/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts index f4c2d84aaa4c..838275876e6d 100644 --- a/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts +++ b/apps/judicial-system/backend/src/app/modules/case/filters/cases.filter.ts @@ -263,7 +263,6 @@ const getDefenceUserCasesQueryFilter = (user: User): WhereOptions => { } export const getCasesQueryFilter = (user: User): WhereOptions => { - // TODO: Convert to switch if (isProsecutionUser(user)) { return getProsecutionUserCasesQueryFilter(user) } diff --git a/apps/judicial-system/backend/src/app/modules/case/interceptors/transition.interceptor.ts b/apps/judicial-system/backend/src/app/modules/case/interceptors/transition.interceptor.ts deleted file mode 100644 index d95e51de802e..000000000000 --- a/apps/judicial-system/backend/src/app/modules/case/interceptors/transition.interceptor.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Observable } from 'rxjs' -import { map } from 'rxjs/operators' - -import { - CallHandler, - ExecutionContext, - Injectable, - NestInterceptor, -} from '@nestjs/common' - -import { - CaseFileCategory, - CaseState, - CaseTransition, - EventType, - isIndictmentCase, - isTrafficViolationCase, - User, -} from '@island.is/judicial-system/types' - -import { nowFactory } from '../../../factories' -import { formatConfirmedIndictmentKey } from '../../../formatters/formatters' -import { AwsS3Service } from '../../aws-s3' -import { EventLogService } from '../../event-log' -import { TransitionCaseDto } from '../dto/transitionCase.dto' -import { Case } from '../models/case.model' -import { PDFService } from '../pdf.service' - -@Injectable() -export class TransitionInterceptor implements NestInterceptor { - constructor( - private readonly eventLogService: EventLogService, - private readonly awsService: AwsS3Service, - private readonly pdfService: PDFService, - ) {} - - async intercept( - context: ExecutionContext, - next: CallHandler, - ): Promise> { - const request = context.switchToHttp().getRequest() - const theCase: Case = request.case - const dto: TransitionCaseDto = request.body - const user: User = request.user - - if ( - isIndictmentCase(theCase.type) && - !isTrafficViolationCase(theCase.indictmentSubtypes, theCase.type) && - theCase.state === CaseState.WAITING_FOR_CONFIRMATION && - dto.transition === CaseTransition.SUBMIT - ) { - for (const indictment of theCase.caseFiles?.filter( - (cf) => cf.category === CaseFileCategory.INDICTMENT && cf.key, - ) ?? []) { - // Get indictment PDF from S3 - const file = await this.awsService.getObject(indictment.key ?? '') - - // Create a stamped indictment PDF - const confirmedIndictment = - await this.pdfService.getConfirmedIndictmentPdf( - { - actor: user.name, - institution: user.institution?.name ?? '', - date: nowFactory(), - }, - file, - ) - - // Save the PDF to S3 - await this.awsService.putObject( - formatConfirmedIndictmentKey(indictment.key), - confirmedIndictment.toString('binary'), - ) - } - } - - return next.handle().pipe( - map((data: Case) => { - if (isIndictmentCase(data.type) && data.state === CaseState.SUBMITTED) { - this.eventLogService.create({ - eventType: EventType.INDICTMENT_CONFIRMED, - caseId: data.id, - nationalId: user.nationalId, - userRole: user.role, - }) - } - - return data - }), - ) - } -} diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts index 585a3e7c04f4..b122cb8a7630 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts @@ -106,6 +106,27 @@ export class InternalCaseController { ) } + @UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases)) + @Post( + `case/:caseId/${messageEndpoint[MessageType.DELIVERY_TO_COURT_INDICTMENT]}`, + ) + @ApiOkResponse({ + type: DeliverResponse, + description: 'Delivers an indictment to court', + }) + deliverIndictmentToCourt( + @Param('caseId') caseId: string, + @CurrentCase() theCase: Case, + @Body() deliverDto: DeliverDto, + ): Promise { + this.logger.debug(`Delivering the indictment for case ${caseId} to court`) + + return this.internalCaseService.deliverIndictmentToCourt( + theCase, + deliverDto.user, + ) + } + @UseGuards(CaseExistsGuard, new CaseTypeGuard(indictmentCases)) @Post( `case/:caseId/${ diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index 690b48e5e69e..020a22acc5e8 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -23,12 +23,10 @@ import { CaseOrigin, CaseState, CaseType, - EventType, - type IndictmentConfirmation, - isCompletedCase, isIndictmentCase, isProsecutionUser, isRestrictionCase, + isTrafficViolationCase, NotificationType, restrictionCases, type User as TUser, @@ -37,8 +35,6 @@ import { import { nowFactory, uuidFactory } from '../../factories' import { - createCaseFilesRecord, - createIndictment, getCourtRecordPdfAsBuffer, getCourtRecordPdfAsString, getCustodyNoticePdfAsString, @@ -53,7 +49,7 @@ import { CaseEvent, EventService } from '../event' import { EventLogService } from '../event-log' import { CaseFile, FileService } from '../file' import { IndictmentCount, IndictmentCountService } from '../indictment-count' -import { CourtDocumentType, PoliceService } from '../police' +import { PoliceDocument, PoliceDocumentType, PoliceService } from '../police' import { UserService } from '../user' import { InternalCreateCaseDto } from './dto/internalCreateCase.dto' import { archiveFilter } from './filters/case.archiveFilter' @@ -63,6 +59,7 @@ import { CaseArchive } from './models/caseArchive.model' import { DateLog } from './models/dateLog.model' import { DeliverResponse } from './models/deliver.response' import { caseModuleConfig } from './case.config' +import { PDFService } from './pdf.service' const caseEncryptionProperties: (keyof Case)[] = [ 'description', @@ -160,6 +157,7 @@ export class InternalCaseService { private readonly defendantService: DefendantService, @Inject(forwardRef(() => EventLogService)) private readonly eventLogService: EventLogService, + private readonly pdfService: PDFService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -284,135 +282,11 @@ export class InternalCaseService { }) } - private async getCaseFilesRecordPdf( - theCase: Case, - policeCaseNumber: string, - ): Promise { - if (isCompletedCase(theCase.state)) { - try { - return await this.awsS3Service.getObject( - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - } catch { - // Ignore the error and try the original key - } - } - - try { - return await this.awsS3Service.getObject( - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - } catch { - // Ignore the error and generate the pdf - } - - const caseFiles = theCase.caseFiles - ?.filter( - (caseFile) => - caseFile.policeCaseNumber === policeCaseNumber && - caseFile.category === CaseFileCategory.CASE_FILE && - caseFile.type === 'application/pdf' && - caseFile.key && - caseFile.chapter !== null && - caseFile.orderWithinChapter !== null, - ) - ?.sort( - (caseFile1, caseFile2) => - (caseFile1.chapter ?? 0) - (caseFile2.chapter ?? 0) || - (caseFile1.orderWithinChapter ?? 0) - - (caseFile2.orderWithinChapter ?? 0), - ) - ?.map((caseFile) => async () => { - const buffer = await this.awsS3Service - .getObject(caseFile.key ?? '') - .catch((reason) => { - // Tolerate failure, but log error - this.logger.error( - `Unable to get file ${caseFile.id} of case ${theCase.id} from AWS S3`, - { reason }, - ) - }) - - return { - chapter: caseFile.chapter as number, - date: caseFile.displayDate ?? caseFile.created, - name: caseFile.userGeneratedFilename ?? caseFile.name, - buffer: buffer ?? undefined, - } - }) - - const pdf = await createCaseFilesRecord( - theCase, - policeCaseNumber, - caseFiles ?? [], - this.formatMessage, - ) - - await this.awsS3Service - .putObject( - `indictments/${isCompletedCase(theCase.state) ? 'completed/' : ''}${ - theCase.id - }/${policeCaseNumber}/caseFilesRecord.pdf`, - pdf.toString('binary'), - ) - .catch((reason) => { - this.logger.error( - `Failed to upload case files record pdf to AWS S3 for case ${theCase.id} and police case ${policeCaseNumber}`, - { reason }, - ) - }) - - return pdf - } - - private async throttleUploadCaseFilesRecordPdfToCourt( - theCase: Case, - policeCaseNumber: string, - user: TUser, - ): Promise { - // Serialize all case files record pdf deliveries in this process - await this.throttle.catch((reason) => { - this.logger.info('Previous case files record pdf delivery failed', { - reason, - }) - }) - - await this.refreshFormatMessage() - - return this.getCaseFilesRecordPdf(theCase, policeCaseNumber) - .then((pdf) => { - const fileName = this.formatMessage(courtUpload.caseFilesRecord, { - policeCaseNumber, - }) - - return this.courtService.createDocument( - user, - theCase.id, - theCase.courtId, - theCase.courtCaseNumber, - CourtDocumentFolder.CASE_DOCUMENTS, - fileName, - `${fileName}.pdf`, - 'application/pdf', - pdf, - ) - }) - .then(() => { - return true - }) - .catch((error) => { - // Tolerate failure, but log error - this.logger.warn( - `Failed to upload case files record pdf to court for case ${theCase.id}`, - { error }, - ) - - return false - }) - } - private getSignedRulingPdf(theCase: Case) { - return this.awsS3Service.getObject(`generated/${theCase.id}/ruling.pdf`) + return this.awsS3Service.getGeneratedObject( + theCase.type, + `${theCase.id}/ruling.pdf`, + ) } private async deliverSignedRulingPdfToCourt( @@ -628,20 +502,77 @@ export class InternalCaseService { }) } + async deliverIndictmentToCourt( + theCase: Case, + user: TUser, + ): Promise { + return this.pdfService + .getIndictmentPdf(theCase) + .then(async (pdf) => { + await this.refreshFormatMessage() + + const fileName = this.formatMessage(courtUpload.indictment) + + return this.courtService.createDocument( + user, + theCase.id, + theCase.courtId, + theCase.courtCaseNumber, + CourtDocumentFolder.INDICTMENT_DOCUMENTS, + fileName, + `${fileName}.pdf`, + 'application/pdf', + pdf, + ) + }) + .then(() => ({ delivered: true })) + .catch((reason) => { + // Tolerate failure, but log error + this.logger.warn( + `Failed to upload indictment pdf to court for case ${theCase.id}`, + { reason }, + ) + + return { delivered: false } + }) + } + async deliverCaseFilesRecordToCourt( theCase: Case, policeCaseNumber: string, user: TUser, ): Promise { - this.throttle = this.throttleUploadCaseFilesRecordPdfToCourt( - theCase, - policeCaseNumber, - user, - ) + return this.pdfService + .getCaseFilesRecordPdf(theCase, policeCaseNumber) + .then(async (pdf) => { + await this.refreshFormatMessage() + + const fileName = this.formatMessage(courtUpload.caseFilesRecord, { + policeCaseNumber, + }) - const delivered = await this.throttle + return this.courtService.createDocument( + user, + theCase.id, + theCase.courtId, + theCase.courtCaseNumber, + CourtDocumentFolder.CASE_DOCUMENTS, + fileName, + `${fileName}.pdf`, + 'application/pdf', + pdf, + ) + }) + .then(() => ({ delivered: true })) + .catch((reason) => { + // Tolerate failure, but log reason + this.logger.warn( + `Failed to upload case files record pdf to court for case ${theCase.id}`, + { reason }, + ) - return { delivered } + return { delivered: false } + }) } async archiveCaseFilesRecord( @@ -649,26 +580,12 @@ export class InternalCaseService { policeCaseNumber: string, ): Promise { return this.awsS3Service - .copyObject( - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + .archiveObject( + theCase.type, + theCase.state, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, ) - .then(() => { - // Fire and forget, no need to wait for the result - this.awsS3Service - .deleteObject( - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - .catch((reason) => { - // Tolerate failure, but log what happened - this.logger.error( - `Could not delete case files record for case ${theCase.id} and police case ${policeCaseNumber} from AWS S3`, - { reason }, - ) - }) - - return { delivered: true } - }) + .then(() => ({ delivered: true })) .catch((reason) => { this.logger.error( `Failed to archive case files record for case ${theCase.id} and police case ${policeCaseNumber}`, @@ -685,9 +602,9 @@ export class InternalCaseService { ): Promise { await this.refreshFormatMessage() - const delivered = await this.upploadRequestPdfToCourt(theCase, user) - - return { delivered } + return this.upploadRequestPdfToCourt(theCase, user).then((delivered) => ({ + delivered, + })) } async deliverCourtRecordToCourt( @@ -696,9 +613,9 @@ export class InternalCaseService { ): Promise { await this.refreshFormatMessage() - const delivered = await this.uploadCourtRecordPdfToCourt(theCase, user) - - return { delivered } + return this.uploadCourtRecordPdfToCourt(theCase, user).then( + (delivered) => ({ delivered }), + ) } async deliverSignedRulingToCourt( @@ -707,9 +624,9 @@ export class InternalCaseService { ): Promise { await this.refreshFormatMessage() - const delivered = await this.deliverSignedRulingPdfToCourt(theCase, user) - - return { delivered } + return this.deliverSignedRulingPdfToCourt(theCase, user).then( + (delivered) => ({ delivered }), + ) } async deliverCaseConclusionToCourt( @@ -830,7 +747,7 @@ export class InternalCaseService { private async deliverCaseToPoliceWithFiles( theCase: Case, user: TUser, - courtDocuments: { type: CourtDocumentType; courtDocument: string }[], + courtDocuments: PoliceDocument[], ): Promise { const originalAncestor = await this.findOriginalAncestor(theCase) @@ -872,13 +789,13 @@ export class InternalCaseService { .then(async () => { const courtDocuments = [ { - type: CourtDocumentType.RVKR, + type: PoliceDocumentType.RVKR, courtDocument: Base64.btoa( await getRequestPdfAsString(theCase, this.formatMessage), ), }, { - type: CourtDocumentType.RVTB, + type: PoliceDocumentType.RVTB, courtDocument: Base64.btoa( await getCourtRecordPdfAsString(theCase, this.formatMessage), ), @@ -888,7 +805,7 @@ export class InternalCaseService { ) && theCase.state === CaseState.ACCEPTED ? [ { - type: CourtDocumentType.RVVI, + type: PoliceDocumentType.RVVI, courtDocument: Base64.btoa( await getCustodyNoticePdfAsString( theCase, @@ -929,13 +846,18 @@ export class InternalCaseService { caseFile.key, ) .map(async (caseFile) => { - const file = await this.awsS3Service.getObject(caseFile.key ?? '') + // TODO: Tolerate failure, but log error + const file = await this.awsS3Service.getObject( + theCase.type, + theCase.state, + caseFile.key, + ) return { type: caseFile.category === CaseFileCategory.COURT_RECORD - ? CourtDocumentType.RVTB - : CourtDocumentType.RVDO, + ? PoliceDocumentType.RVTB + : PoliceDocumentType.RVDO, courtDocument: Base64.btoa(file.toString('binary')), } }) ?? [], @@ -959,91 +881,70 @@ export class InternalCaseService { theCase: Case, user: TUser, ): Promise { - const delivered = await Promise.all( - theCase.caseFiles - ?.filter( - (caseFile) => - caseFile.category === CaseFileCategory.INDICTMENT && caseFile.key, - ) - .map(async (caseFile) => { - const file = await this.awsS3Service.getObject(caseFile.key ?? '') - - return { - type: CourtDocumentType.RVAS, - courtDocument: Base64.btoa(file.toString('binary')), - } - }) ?? [], - ) - .then(async (indictmentDocuments) => { - if (indictmentDocuments.length === 0) { - let confirmation: IndictmentConfirmation = undefined - const confirmationEvent = - await this.eventLogService.findEventTypeByCaseId( - EventType.INDICTMENT_CONFIRMED, - theCase.id, - ) - - if (confirmationEvent && confirmationEvent.nationalId) { - const actor = await this.userService.findByNationalId( - confirmationEvent.nationalId, - ) - - confirmation = { - actor: actor.name, - institution: actor.institution?.name ?? '', - date: confirmationEvent.created, - } - } - - const file = await this.refreshFormatMessage().then(async () => - createIndictment(theCase, this.formatMessage, confirmation), - ) + try { + let policeDocuments: PoliceDocument[] - indictmentDocuments.push({ - type: CourtDocumentType.RVAS, - courtDocument: Base64.btoa(file.toString('binary')), - }) - } + if (isTrafficViolationCase(theCase)) { + const file = await this.pdfService.getIndictmentPdf(theCase) - return this.deliverCaseToPoliceWithFiles( - theCase, - user, - indictmentDocuments, - ) - }) - .catch((reason) => { - // Tolerate failure, but log error - this.logger.error( - `Failed to deliver indictment for case ${theCase.id} to police`, + policeDocuments = [ { - reason, + type: PoliceDocumentType.RVAS, + courtDocument: Base64.btoa(file.toString('binary')), }, + ] + } else { + policeDocuments = await Promise.all( + theCase.caseFiles + ?.filter( + (caseFile) => + caseFile.category === CaseFileCategory.INDICTMENT && + caseFile.key, + ) + .map(async (caseFile) => { + // TODO: Tolerate failure, but log error + const file = await this.fileService.getCaseFileFromS3( + theCase, + caseFile, + ) + + return { + type: PoliceDocumentType.RVAS, + courtDocument: Base64.btoa(file.toString('binary')), + } + }) ?? [], ) + } - return false - }) + const delivered = await this.deliverCaseToPoliceWithFiles( + theCase, + user, + policeDocuments, + ) - return { delivered } + return { delivered } + } catch (error) { + // Tolerate failure, but log error + this.logger.error( + `Failed to deliver indictment for case ${theCase.id} to police`, + { error }, + ) + + return { delivered: false } + } } - private async throttleUploadCaseFilesRecordPdfToPolice( + async deliverCaseFilesRecordToPolice( theCase: Case, policeCaseNumber: string, user: TUser, - ): Promise { - // Serialize all case files record pdf deliveries in this process - await this.throttle.catch((reason) => { - this.logger.info('Previous case files record pdf delivery failed', { - reason, - }) - }) - - return this.refreshFormatMessage() - .then(() => this.getCaseFilesRecordPdf(theCase, policeCaseNumber)) + ): Promise { + const delivered = await this.pdfService + .getCaseFilesRecordPdf(theCase, policeCaseNumber) .then((pdf) => this.deliverCaseToPoliceWithFiles(theCase, user, [ { - type: CourtDocumentType.RVMG, + type: PoliceDocumentType.RVMG, courtDocument: Base64.btoa(pdf.toString('binary')), }, ]), @@ -1057,20 +958,6 @@ export class InternalCaseService { return false }) - } - - async deliverCaseFilesRecordToPolice( - theCase: Case, - policeCaseNumber: string, - user: TUser, - ): Promise { - this.throttle = this.throttleUploadCaseFilesRecordPdfToPolice( - theCase, - policeCaseNumber, - user, - ) - - const delivered = await this.throttle return { delivered } } @@ -1083,7 +970,7 @@ export class InternalCaseService { .then((pdf) => this.deliverCaseToPoliceWithFiles(theCase, user, [ { - type: CourtDocumentType.RVUR, + type: PoliceDocumentType.RVUR, courtDocument: Base64.btoa(pdf.toString('binary')), }, ]), @@ -1109,10 +996,15 @@ export class InternalCaseService { theCase.caseFiles ?.filter((file) => file.category === CaseFileCategory.APPEAL_RULING) .map(async (caseFile) => { - const file = await this.awsS3Service.getObject(caseFile.key ?? '') + // TODO: Tolerate failure, but log error + const file = await this.awsS3Service.getObject( + theCase.type, + theCase.state, + caseFile.key, + ) return { - type: CourtDocumentType.RVUL, + type: PoliceDocumentType.RVUL, courtDocument: Base64.btoa(file.toString('binary')), } }) ?? [], diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index a0e44ad60792..1be2398a862e 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -422,9 +422,10 @@ export class LimitedAccessCaseService { ), ) ?? [] + // TODO: speed this up by fetching all files in parallel for (const file of caseFilesByCategory) { await this.awsS3Service - .getObject(file.key ?? '') + .getObject(theCase.type, theCase.state, file.key) .then((content) => filesToZip.push({ data: content, name: file.name })) .catch((reason) => // Tolerate failure, but log what happened diff --git a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts index 81117d9db4cf..fb6261333a6a 100644 --- a/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts +++ b/apps/judicial-system/backend/src/app/modules/case/models/case.model.ts @@ -1013,4 +1013,12 @@ export class Case extends Model { }) @ApiPropertyOptional({ enum: IndictmentCaseReviewDecision }) indictmentReviewDecision?: IndictmentCaseReviewDecision + + /********** + * The md5 hash of the confirmed generated indictment + * Only used for traffic violation cases + **********/ + @Column({ type: DataType.STRING, allowNull: true }) + @ApiPropertyOptional({ type: String }) + indictmentHash?: string } diff --git a/apps/judicial-system/backend/src/app/modules/case/pdf.service.ts b/apps/judicial-system/backend/src/app/modules/case/pdf.service.ts index 1f9f9c5fa26a..d1b1d966820b 100644 --- a/apps/judicial-system/backend/src/app/modules/case/pdf.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/pdf.service.ts @@ -1,8 +1,12 @@ +import CryptoJS from 'crypto-js' + import { + BadRequestException, Inject, Injectable, InternalServerErrorException, } from '@nestjs/common' +import { InjectModel } from '@nestjs/sequelize' import { FormatMessage, IntlService } from '@island.is/cms-translations' import type { Logger } from '@island.is/logging' @@ -10,10 +14,9 @@ import { LOGGER_PROVIDER } from '@island.is/logging' import { CaseFileCategory, - CaseState, EventType, - type IndictmentConfirmation, - isCompletedCase, + hasIndictmentCaseBeenSubmittedToCourt, + isTrafficViolationCase, type User as TUser, } from '@island.is/judicial-system/types' @@ -24,10 +27,9 @@ import { getCustodyNoticePdfAsBuffer, getRequestPdfAsBuffer, getRulingPdfAsBuffer, + IndictmentConfirmation, } from '../../formatters' -import { createConfirmedIndictment } from '../../formatters/confirmedIndictmentPdf' import { AwsS3Service } from '../aws-s3' -import { EventLogService } from '../event-log' import { UserService } from '../user' import { Case } from './models/case.model' @@ -38,8 +40,8 @@ export class PDFService { constructor( private readonly awsS3Service: AwsS3Service, private readonly intlService: IntlService, - private readonly eventLogService: EventLogService, private readonly userService: UserService, + @InjectModel(Case) private readonly caseModel: typeof Case, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -87,36 +89,50 @@ export class PDFService { ) ?.map((caseFile) => async () => { const buffer = await this.awsS3Service - .getObject(caseFile.key ?? '') + .getObject(theCase.type, theCase.state, caseFile.key) .catch((reason) => { // Tolerate failure, but log error this.logger.error( `Unable to get file ${caseFile.id} of case ${theCase.id} from AWS S3`, { reason }, ) + + return undefined }) return { chapter: caseFile.chapter as number, date: caseFile.displayDate ?? caseFile.created, name: caseFile.userGeneratedFilename ?? caseFile.name, - buffer: buffer ?? undefined, + buffer: buffer, } }) - return createCaseFilesRecord( + const generatedPdf = await createCaseFilesRecord( theCase, policeCaseNumber, caseFiles ?? [], this.formatMessage, ) + + if (hasIndictmentCaseBeenSubmittedToCourt(theCase.state)) { + // No need to wait for the upload to finish + this.tryUploadPdfToS3( + theCase, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + generatedPdf, + ) + } + + return generatedPdf } async getCourtRecordPdf(theCase: Case, user: TUser): Promise { if (theCase.courtRecordSignatureDate) { try { - return await this.awsS3Service.getObject( - `generated/${theCase.id}/courtRecord.pdf`, + return await this.awsS3Service.getGeneratedObject( + theCase.type, + `${theCase.id}/courtRecord.pdf`, ) } catch (error) { this.logger.info( @@ -140,8 +156,9 @@ export class PDFService { async getRulingPdf(theCase: Case): Promise { if (theCase.rulingSignatureDate) { try { - return await this.awsS3Service.getObject( - `generated/${theCase.id}/ruling.pdf`, + return await this.awsS3Service.getGeneratedObject( + theCase.type, + `${theCase.id}/ruling.pdf`, ) } catch (error) { this.logger.info( @@ -162,62 +179,101 @@ export class PDFService { return getCustodyNoticePdfAsBuffer(theCase, this.formatMessage) } + private async tryGetPdfFromS3( + theCase: Case, + key: string, + ): Promise { + return await this.awsS3Service + .getObject(theCase.type, theCase.state, key) + .catch(() => undefined) // Ignore errors and return undefined + } + + private tryUploadPdfToS3(theCase: Case, key: string, pdf: Buffer) { + this.awsS3Service + .putObject(theCase.type, theCase.state, key, pdf.toString('binary')) + .catch((reason) => { + this.logger.error(`Failed to upload pdf ${key} to AWS S3`, { reason }) + }) + } + async getIndictmentPdf(theCase: Case): Promise { - await this.refreshFormatMessage() + if (!isTrafficViolationCase(theCase)) { + throw new BadRequestException( + `Case ${theCase.id} is not a traffic violation case`, + ) + } - let confirmation: IndictmentConfirmation = undefined - const confirmationEvent = await this.eventLogService.findEventTypeByCaseId( - EventType.INDICTMENT_CONFIRMED, - theCase.id, - ) + let confirmation: IndictmentConfirmation | undefined = undefined - if (confirmationEvent && confirmationEvent.nationalId) { - const actor = await this.userService.findByNationalId( - confirmationEvent.nationalId, + if (hasIndictmentCaseBeenSubmittedToCourt(theCase.state)) { + if (theCase.indictmentHash) { + const existingPdf = await this.tryGetPdfFromS3( + theCase, + `${theCase.id}/indictment.pdf`, + ) + + if (existingPdf) { + return existingPdf + } + } + + const confirmationEvent = theCase.eventLogs?.find( + (event) => event.eventType === EventType.INDICTMENT_CONFIRMED, ) - confirmation = { - actor: actor.name, - institution: actor.institution?.name ?? '', - date: confirmationEvent.created, + if (confirmationEvent && confirmationEvent.nationalId) { + const actor = await this.userService.findByNationalId( + confirmationEvent.nationalId, + ) + + confirmation = { + actor: actor.name, + institution: actor.institution?.name ?? '', + date: confirmationEvent.created, + } } } - return createIndictment(theCase, this.formatMessage, confirmation) - } + await this.refreshFormatMessage() - async getConfirmedIndictmentPdf( - confirmation: IndictmentConfirmation, - indictmentPDF: Buffer, - ): Promise { - return createConfirmedIndictment(confirmation, indictmentPDF) + const generatedPdf = await createIndictment( + theCase, + this.formatMessage, + confirmation, + ) + + if (hasIndictmentCaseBeenSubmittedToCourt(theCase.state) && confirmation) { + const indictmentHash = CryptoJS.MD5( + generatedPdf.toString('binary'), + ).toString(CryptoJS.enc.Hex) + + // No need to wait for this to finish + this.caseModel + .update({ indictmentHash }, { where: { id: theCase.id } }) + .then(() => + this.tryUploadPdfToS3( + theCase, + `${theCase.id}/indictment.pdf`, + generatedPdf, + ), + ) + } + + return generatedPdf } async getCaseFilesRecordPdf( theCase: Case, policeCaseNumber: string, ): Promise { - if ( - ![CaseState.NEW, CaseState.DRAFT, CaseState.SUBMITTED].includes( - theCase.state, + if (hasIndictmentCaseBeenSubmittedToCourt(theCase.state)) { + const existingPdf = await this.tryGetPdfFromS3( + theCase, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, ) - ) { - if (isCompletedCase(theCase.state)) { - try { - return await this.awsS3Service.getObject( - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - } catch { - // Ignore the error and try the original key - } - } - try { - return await this.awsS3Service.getObject( - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - } catch { - // Ignore the error and generate the pdf + if (existingPdf) { + return existingPdf } } @@ -226,6 +282,6 @@ export class PDFService { policeCaseNumber, ) - return this.throttle + return await this.throttle } } diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getAll.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getAll.spec.ts index bc96214b669d..9abf249fb601 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getAll.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getAll.spec.ts @@ -49,7 +49,7 @@ describe('CaseController - Get all', () => { const mockGetCasesQueryFilter = getCasesQueryFilter as jest.Mock mockGetCasesQueryFilter.mockReturnValueOnce(filter) const mockFindAll = mockCaseModel.findAll as jest.Mock - mockFindAll.mockReturnValueOnce(cases) + mockFindAll.mockResolvedValueOnce(cases) then = await givenWhenThen() }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCaseFilesRecordPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCaseFilesRecordPdf.spec.ts index 79e03ac601df..b982b0dfba58 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCaseFilesRecordPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCaseFilesRecordPdf.spec.ts @@ -3,7 +3,11 @@ import { uuid } from 'uuidv4' import { BadRequestException } from '@nestjs/common' -import { CaseFileCategory, CaseState } from '@island.is/judicial-system/types' +import { + CaseFileCategory, + CaseState, + CaseType, +} from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -38,11 +42,12 @@ describe('CaseController - Get case files record pdf', () => { ] as CaseFile[] const theCase = { id: caseId, - state: CaseState.ACCEPTED, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, policeCaseNumbers: [uuid(), policeCaseNumber, uuid()], caseFiles, } as Case - const pdf = uuid() + const pdf = Buffer.from(uuid()) const res = { end: jest.fn() } as unknown as Response let mockawsS3Service: AwsS3Service @@ -54,6 +59,8 @@ describe('CaseController - Get case files record pdf', () => { mockawsS3Service = awsS3Service const mockGetObject = mockawsS3Service.getObject as jest.Mock mockGetObject.mockRejectedValue(new Error('Some error')) + const mockPutObject = mockawsS3Service.putObject as jest.Mock + mockPutObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async (policeCaseNumber: string) => { const then = {} as Then @@ -82,13 +89,10 @@ describe('CaseController - Get case files record pdf', () => { }) it('should generate pdf after failing to get it from AWS S3', () => { - expect(mockawsS3Service.getObject).toHaveBeenNthCalledWith( - 1, - `indictments/completed/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - expect(mockawsS3Service.getObject).toHaveBeenNthCalledWith( - 2, - `indictments/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, + expect(mockawsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, ) expect(createCaseFilesRecord).toHaveBeenCalledWith( theCase, @@ -96,28 +100,20 @@ describe('CaseController - Get case files record pdf', () => { expect.any(Array), expect.any(Function), ) + expect(mockawsS3Service.putObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, + pdf.toString('binary'), + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) - describe('pdf returned from AWS S3 indictment completed folder', () => { - beforeEach(async () => { - const mockGetObject = mockawsS3Service.getObject as jest.Mock - mockGetObject.mockReturnValueOnce(pdf) - - await givenWhenThen(policeCaseNumber) - }) - - it('should return pdf', () => { - expect(res.end).toHaveBeenCalledWith(pdf) - }) - }) - - describe('pdf returned from AWS S3 indictment folder', () => { + describe('pdf returned from AWS S3', () => { beforeEach(async () => { const mockGetObject = mockawsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some error')) - mockGetObject.mockReturnValueOnce(pdf) + mockGetObject.mockResolvedValueOnce(pdf) await givenWhenThen(policeCaseNumber) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordPdf.spec.ts index b2e92770f532..143d68c2ab8b 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordPdf.spec.ts @@ -3,7 +3,7 @@ import { uuid } from 'uuidv4' import { Logger } from '@island.is/logging' -import { User } from '@island.is/judicial-system/types' +import { CaseState, CaseType, User } from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -33,9 +33,16 @@ describe('CaseController - Get court record pdf', () => { beforeEach(async () => { const { awsS3Service, logger, caseController } = await createTestingCaseModule() + mockAwsS3Service = awsS3Service mockLogger = logger + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) + const getMock = getCourtRecordPdfAsBuffer as jest.Mock + getMock.mockRejectedValue(new Error('Some error')) + givenWhenThen = async ( caseId: string, user: User, @@ -57,23 +64,29 @@ describe('CaseController - Get court record pdf', () => { describe('AWS S3 pdf returned', () => { const user = { id: uuid() } as User const caseId = uuid() + const caseType = CaseType.PAROLE_REVOCATION + const caseSate = CaseState.ACCEPTED const theCase = { id: caseId, + type: caseType, + state: caseSate, courtRecordSignatureDate: nowFactory(), } as Case const res = { end: jest.fn() } as unknown as Response const pdf = uuid() beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, user, theCase, res) }) it('should lookup pdf', () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/courtRecord.pdf`, + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/courtRecord.pdf`, ) expect(res.end).toHaveBeenCalledWith(pdf) }) @@ -86,13 +99,11 @@ describe('CaseController - Get court record pdf', () => { id: caseId, courtRecordSignatureDate: nowFactory(), } as Case - const error = new Error('Some ignored error') + const error = new Error('Some error') const res = { end: jest.fn() } as unknown as Response const pdf = uuid() beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(error) const getMock = getCourtRecordPdfAsBuffer as jest.Mock getMock.mockResolvedValueOnce(pdf) @@ -124,8 +135,6 @@ describe('CaseController - Get court record pdf', () => { const res = {} as Response beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) const getMock = getCourtRecordPdfAsBuffer as jest.Mock getMock.mockRejectedValueOnce(new Error('Some error')) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordSignatureConfirmation.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordSignatureConfirmation.spec.ts index 1edc06628158..59bc8a99c6a4 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordSignatureConfirmation.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getCourtRecordSignatureConfirmation.spec.ts @@ -38,6 +38,14 @@ describe('CaseController - Get court record signature confirmation', () => { mockAwsS3Service = awsS3Service mockCaseModel = caseModel + const mockPutGeneratedObject = + mockAwsS3Service.putGeneratedObject as jest.Mock + mockPutGeneratedObject.mockRejectedValue(new Error('Some error')) + const mockUpdate = mockCaseModel.update as jest.Mock + mockUpdate.mockRejectedValue(new Error('Some error')) + const mockFindOne = mockCaseModel.findOne as jest.Mock + mockFindOne.mockRejectedValue(new Error('Some error')) + const mockTransaction = sequelize.transaction as jest.Mock transaction = {} as Transaction mockTransaction.mockImplementationOnce( @@ -92,8 +100,9 @@ describe('CaseController - Get court record signature confirmation', () => { let then: Then beforeEach(async () => { - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockResolvedValueOnce(Promise.resolve()) + const mockPutGeneratedObject = + mockAwsS3Service.putGeneratedObject as jest.Mock + mockPutGeneratedObject.mockResolvedValueOnce(Promise.resolve()) const mockUpdate = mockCaseModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([1, [theCase]]) const mockFindOne = mockCaseModel.findOne as jest.Mock @@ -120,9 +129,6 @@ describe('CaseController - Get court record signature confirmation', () => { let then: Then beforeEach(async () => { - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, user, theCase, documentToken) }) @@ -138,10 +144,9 @@ describe('CaseController - Get court record signature confirmation', () => { let then: Then beforeEach(async () => { - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockResolvedValueOnce(Promise.resolve()) - const mockUpdate = mockCaseModel.update as jest.Mock - mockUpdate.mockRejectedValueOnce(new Error('Some error')) + const mockPutGeneratedObject = + mockAwsS3Service.putGeneratedObject as jest.Mock + mockPutGeneratedObject.mockResolvedValueOnce(Promise.resolve()) then = await givenWhenThen(caseId, user, theCase, documentToken) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getIndictmentPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getIndictmentPdf.spec.ts index 5cc6729c4027..015d1f3c01ff 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getIndictmentPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getIndictmentPdf.spec.ts @@ -1,9 +1,16 @@ import { Response } from 'express' import { uuid } from 'uuidv4' +import { + CaseState, + CaseType, + IndictmentSubtype, +} from '@island.is/judicial-system/types' + import { createTestingCaseModule } from '../createTestingCaseModule' import { createIndictment } from '../../../../formatters' +import { AwsS3Service } from '../../../aws-s3' import { Case } from '../../models/case.model' jest.mock('../../../../formatters/indictmentPdf') @@ -16,16 +23,29 @@ type GivenWhenThen = () => Promise describe('CaseController - Get indictment pdf', () => { const caseId = uuid() + const policeCaseNumber = uuid() const theCase = { id: caseId, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, + policeCaseNumbers: [policeCaseNumber], + indictmentSubtypes: { + [policeCaseNumber]: [IndictmentSubtype.TRAFFIC_VIOLATION], + }, + indictmentHash: uuid(), } as Case - const pdf = uuid() + const pdf = Buffer.from(uuid()) const res = { end: jest.fn() } as unknown as Response + let mockAwsS3Service: AwsS3Service let givenWhenThen: GivenWhenThen beforeEach(async () => { - const { caseController } = await createTestingCaseModule() + const { awsS3Service, caseController } = await createTestingCaseModule() + + mockAwsS3Service = awsS3Service + const mockGetObject = mockAwsS3Service.getObject as jest.Mock + mockGetObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async () => { const then = {} as Then @@ -48,7 +68,12 @@ describe('CaseController - Get indictment pdf', () => { await givenWhenThen() }) - it('should generate pdf', () => { + it('should generate pdf after failing to get it from AWS S3', () => { + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/indictment.pdf`, + ) expect(createIndictment).toHaveBeenCalledWith( theCase, expect.any(Function), @@ -57,4 +82,17 @@ describe('CaseController - Get indictment pdf', () => { expect(res.end).toHaveBeenCalledWith(pdf) }) }) + + describe('pdf returned from AWS S3', () => { + beforeEach(async () => { + const mockGetObject = mockAwsS3Service.getObject as jest.Mock + mockGetObject.mockResolvedValueOnce(pdf) + + await givenWhenThen() + }) + + it('should return pdf', () => { + expect(res.end).toHaveBeenCalledWith(pdf) + }) + }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingPdf.spec.ts index 4be69ad5d793..0f081c9a98ed 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingPdf.spec.ts @@ -3,6 +3,8 @@ import { uuid } from 'uuidv4' import { Logger } from '@island.is/logging' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingCaseModule } from '../createTestingCaseModule' import { nowFactory } from '../../../../factories' @@ -30,9 +32,16 @@ describe('CaseController - Get ruling pdf', () => { beforeEach(async () => { const { awsS3Service, logger, caseController } = await createTestingCaseModule() + mockAwsS3Service = awsS3Service mockLogger = logger + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) + const getMock = getRulingPdfAsBuffer as jest.Mock + getMock.mockRejectedValue(new Error('Some error')) + givenWhenThen = async (caseId: string, theCase: Case, res: Response) => { const then = {} as Then @@ -46,36 +55,32 @@ describe('CaseController - Get ruling pdf', () => { } }) - describe('AWS S3 lookup', () => { - const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = {} as Response - - beforeEach(async () => { - await givenWhenThen(caseId, theCase, res) - }) - - it('should lookup pdf', () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/ruling.pdf`, - ) - }) - }) - describe('AWS S3 pdf returned', () => { const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case + const caseType = CaseType.EXPULSION_FROM_HOME + const caseState = CaseState.REJECTED + const theCase = { + id: caseId, + type: caseType, + state: caseState, + rulingSignatureDate: nowFactory(), + } as Case const res = { end: jest.fn() } as unknown as Response const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, theCase, res) }) it('should return pdf', () => { + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/ruling.pdf`, + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -84,12 +89,9 @@ describe('CaseController - Get ruling pdf', () => { const caseId = uuid() const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case const res = {} as Response - const error = new Error('Some ignored error') + const error = new Error('Some error') beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(error) - await givenWhenThen(caseId, theCase, res) }) @@ -101,43 +103,25 @@ describe('CaseController - Get ruling pdf', () => { }) }) - describe('pdf generated', () => { - const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = {} as Response - - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - - await givenWhenThen(caseId, theCase, res) - }) - - it('should generate pdf', () => { - expect(getRulingPdfAsBuffer).toHaveBeenCalledWith( - theCase, - expect.any(Function), - ) - }) - }) - - describe('pdf generated', () => { + describe('generated pdf returned', () => { const caseId = uuid() const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = {} as Response + const res = { end: jest.fn() } as unknown as Response + const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) + const getMock = getRulingPdfAsBuffer as jest.Mock + getMock.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, theCase, res) }) - it('should generate pdf', () => { + it('should return pdf', () => { expect(getRulingPdfAsBuffer).toHaveBeenCalledWith( theCase, expect.any(Function), ) + expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -158,26 +142,6 @@ describe('CaseController - Get ruling pdf', () => { }) }) - describe('generated pdf returned', () => { - const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = { end: jest.fn() } as unknown as Response - const pdf = {} - - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - const getMock = getRulingPdfAsBuffer as jest.Mock - getMock.mockResolvedValueOnce(pdf) - - await givenWhenThen(caseId, theCase, res) - }) - - it('should return pdf', () => { - expect(res.end).toHaveBeenCalledWith(pdf) - }) - }) - describe('pdf generation fails', () => { const caseId = uuid() const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case @@ -185,11 +149,6 @@ describe('CaseController - Get ruling pdf', () => { const res = {} as Response beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - const getMock = getRulingPdfAsBuffer as jest.Mock - getMock.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, theCase, res) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingSignatureConfirmation.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingSignatureConfirmation.spec.ts index 6ebe21d948ae..c05595c977b2 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingSignatureConfirmation.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/getRulingSignatureConfirmation.spec.ts @@ -65,8 +65,9 @@ describe('CaseController - Get ruling signature confirmation', () => { const mockToday = nowFactory as jest.Mock mockToday.mockReturnValueOnce(date) - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockResolvedValue(uuid()) + const mockPutGeneratedObject = + mockAwsS3Service.putGeneratedObject as jest.Mock + mockPutGeneratedObject.mockResolvedValue(uuid()) const mockUpdate = mockCaseModel.update as jest.Mock mockUpdate.mockResolvedValue([1]) const mockPostMessageToQueue = @@ -125,15 +126,12 @@ describe('CaseController - Get ruling signature confirmation', () => { then = await givenWhenThen(caseId, user, theCase, documentToken) }) - it('should set the ruling signature date', () => { + it('should return success', () => { expect(mockCaseModel.update).toHaveBeenCalledWith( { rulingSignatureDate: date }, { where: { id: caseId }, transaction }, ) - }) - - it('should return success', () => { - expect(mockAwsS3Service.putObject).toHaveBeenCalled() + expect(mockAwsS3Service.putGeneratedObject).toHaveBeenCalled() expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([ { type: MessageType.DELIVERY_TO_COURT_SIGNED_RULING, user, caseId }, { @@ -169,10 +167,7 @@ describe('CaseController - Get ruling signature confirmation', () => { { rulingSignatureDate: date }, { where: { id: caseId }, transaction }, ) - }) - - it('should return success', () => { - expect(mockAwsS3Service.putObject).toHaveBeenCalled() + expect(mockAwsS3Service.putGeneratedObject).toHaveBeenCalled() expect(mockMessageService.sendMessagesToQueue).toHaveBeenCalledWith([ { type: MessageType.DELIVERY_TO_COURT_SIGNED_RULING, user, caseId }, { @@ -269,8 +264,9 @@ describe('CaseController - Get ruling signature confirmation', () => { let then: Then beforeEach(async () => { - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockRejectedValueOnce(new Error('Some error')) + const mockPutGeneratedObject = + mockAwsS3Service.putGeneratedObject as jest.Mock + mockPutGeneratedObject.mockRejectedValueOnce(new Error('Some error')) then = await givenWhenThen(caseId, user, theCase, documentToken) }) @@ -279,7 +275,6 @@ describe('CaseController - Get ruling signature confirmation', () => { expect(then.result.documentSigned).toBe(false) expect(then.result.message).toBeTruthy() expect(then.result.code).toBeUndefined() - expect(mockCaseModel.update).not.toHaveBeenCalled() expect(mockMessageService.sendMessagesToQueue).not.toHaveBeenCalled() }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts index ac0f883e4f10..0c65a57ebf29 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/transition.spec.ts @@ -359,12 +359,22 @@ describe('CaseController - Transition', () => { transition === CaseTransition.DELETE ? null : undefined, courtCaseNumber: transition === CaseTransition.RETURN_INDICTMENT - ? '' + ? null + : undefined, + indictmentHash: + transition === CaseTransition.RETURN_INDICTMENT + ? null : undefined, rulingDate: transition === CaseTransition.COMPLETE ? date : undefined, judgeId: transition === CaseTransition.REDISTRIBUTE ? null : undefined, + indictmentDeniedExplanation: + transition === CaseTransition.SUBMIT ? null : undefined, + indictmentReturnedExplanation: + transition === CaseTransition.ASK_FOR_CONFIRMATION + ? null + : undefined, }, { where: { id: caseId }, transaction }, ) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/caseController/update.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/caseController/update.spec.ts index 117142cff466..3d4b3d6fba78 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/caseController/update.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/caseController/update.spec.ts @@ -190,6 +190,7 @@ describe('CaseController - Update', () => { it('should delete a case file', () => { expect(mockFileService.deleteCaseFile).toHaveBeenCalledWith( + theCase, caseFile, transaction, ) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/archiveCaseFilesRecord.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/archiveCaseFilesRecord.spec.ts index 11ed25dccfda..9ae4785ad11c 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/archiveCaseFilesRecord.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/archiveCaseFilesRecord.spec.ts @@ -2,6 +2,8 @@ import { uuid } from 'uuidv4' import { BadRequestException } from '@nestjs/common' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingCaseModule } from '../createTestingCaseModule' import { AwsS3Service } from '../../../aws-s3' @@ -20,6 +22,8 @@ type GivenWhenThen = ( describe('InternalCaseController - Archive case files record', () => { const caseId = uuid() + const caseType = CaseType.INDICTMENT + const caseState = CaseState.COMPLETED const policeCaseNumber = uuid() let mockawsS3Service: AwsS3Service @@ -30,10 +34,8 @@ describe('InternalCaseController - Archive case files record', () => { await createTestingCaseModule() mockawsS3Service = awsS3Service - const mockCopyObject = mockawsS3Service.copyObject as jest.Mock - mockCopyObject.mockRejectedValue(new Error('Some error')) - const mockDeleteObject = mockawsS3Service.deleteObject as jest.Mock - mockDeleteObject.mockRejectedValue(new Error('Some error')) + const mockArchiveObject = mockawsS3Service.archiveObject as jest.Mock + mockArchiveObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async ( policeCaseNumber: string, @@ -44,6 +46,8 @@ describe('InternalCaseController - Archive case files record', () => { await internalCaseController .archiveCaseFilesRecord(caseId, policeCaseNumber, { id: caseId, + type: caseType, + state: caseState, policeCaseNumbers, } as Case) .then((result) => (then.result = result)) @@ -57,8 +61,8 @@ describe('InternalCaseController - Archive case files record', () => { let then: Then beforeEach(async () => { - const mockCopyObject = mockawsS3Service.copyObject as jest.Mock - mockCopyObject.mockResolvedValueOnce(uuid()) + const mockArchiveObject = mockawsS3Service.archiveObject as jest.Mock + mockArchiveObject.mockResolvedValueOnce(uuid()) then = await givenWhenThen(policeCaseNumber, [ uuid(), @@ -67,20 +71,12 @@ describe('InternalCaseController - Archive case files record', () => { ]) }) - it('should copy the case files record to the AWS S3 indictment completed folder', () => { - expect(mockawsS3Service.copyObject).toHaveBeenCalledWith( - `indictments/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, - `indictments/completed/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - }) - - it('should delete the case files record from the AWS S3 indictment folder', () => { - expect(mockawsS3Service.deleteObject).toHaveBeenCalledWith( - `indictments/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, + it('should archive the case files record', () => { + expect(mockawsS3Service.archiveObject).toHaveBeenCalledWith( + caseType, + caseState, + `${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, ) - }) - - it('should return a success response', () => { expect(then.result).toEqual({ delivered: true }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverAppealToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverAppealToPolice.spec.ts index e00a9c2cf05a..fe04e77ebbf0 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverAppealToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverAppealToPolice.spec.ts @@ -14,7 +14,7 @@ import { createTestingCaseModule } from '../createTestingCaseModule' import { randomDate } from '../../../../test' import { AwsS3Service } from '../../../aws-s3' -import { CourtDocumentType, PoliceService } from '../../../police' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -40,8 +40,8 @@ describe('InternalCaseController - Deliver appeal to police', () => { mockAwsS3Service = awsS3Service mockPoliceService = policeService - const mockGetObject = awsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValue(new Error('Some error')) + const mockGetGeneratedObject = awsS3Service.getObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock mockUpdatePoliceCase.mockRejectedValue(new Error('Some error')) @@ -87,8 +87,8 @@ describe('InternalCaseController - Deliver appeal to police', () => { let then: Then beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(appealRulingPdf) + const mockGetGeneratedObject = mockAwsS3Service.getObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(appealRulingPdf) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock mockUpdatePoliceCase.mockResolvedValueOnce(true) @@ -96,7 +96,11 @@ describe('InternalCaseController - Deliver appeal to police', () => { then = await givenWhenThen(caseId, theCase) }) it('should update the police case', async () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(appealRulingKey) + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + caseType, + caseState, + appealRulingKey, + ) expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( user, caseId, @@ -109,7 +113,7 @@ describe('InternalCaseController - Deliver appeal to police', () => { caseConclusion, [ { - type: CourtDocumentType.RVUL, + type: PoliceDocumentType.RVUL, courtDocument: Base64.btoa(appealRulingPdf), }, ], diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourt.spec.ts index ee2a309ee87c..f8275ed779fc 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourt.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourt.spec.ts @@ -2,7 +2,7 @@ import { uuid } from 'uuidv4' import { BadRequestException } from '@nestjs/common' -import { CaseState, User } from '@island.is/judicial-system/types' +import { CaseState, CaseType, User } from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -33,7 +33,8 @@ describe('InternalCaseController - Deliver case files record to court', () => { const courtCaseNumber = uuid() const theCase = { id: caseId, - state: CaseState.ACCEPTED, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, policeCaseNumbers: [policeCaseNumber], courtId, courtCaseNumber, @@ -45,9 +46,6 @@ describe('InternalCaseController - Deliver case files record to court', () => { let givenWhenThen: GivenWhenThen beforeEach(async () => { - const mockGet = createCaseFilesRecord as jest.Mock - mockGet.mockRejectedValue(new Error('Some error')) - const { awsS3Service, courtService, internalCaseController } = await createTestingCaseModule() @@ -94,37 +92,24 @@ describe('InternalCaseController - Deliver case files record to court', () => { then = await givenWhenThen(caseId, policeCaseNumber, theCase) }) - it('should try to get the pdf from AWS S3 indictment completed folder', () => { - expect(mockAwsS3Service.getObject).toHaveBeenNthCalledWith( - 1, - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + it('should deliver the case files record', () => { + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, ) - }) - - it('should try to get the pdf from AWS S3 indictment folder', () => { - expect(mockAwsS3Service.getObject).toHaveBeenNthCalledWith( - 2, - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - }) - - it('should generate the case files record', async () => { expect(createCaseFilesRecord).toHaveBeenCalledWith( theCase, policeCaseNumber, [], expect.any(Function), ) - }) - - it('should store the case files record in AWS S3', async () => { expect(mockAwsS3Service.putObject).toHaveBeenCalledWith( - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + theCase.type, + theCase.state, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, pdf.toString(), ) - }) - - it('should create a case files record at court', async () => { expect(mockCourtService.createDocument).toHaveBeenCalledWith( user, caseId, @@ -136,41 +121,14 @@ describe('InternalCaseController - Deliver case files record to court', () => { 'application/pdf', pdf, ) - }) - - it('should return a success response', async () => { expect(then.result).toEqual({ delivered: true }) }) }) - describe('pdf returned from AWS S3 indictment completed folder', () => { - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockReturnValueOnce(pdf) - - await givenWhenThen(caseId, policeCaseNumber, theCase) - }) - - it('should use the AWS S3 pdf', () => { - expect(mockCourtService.createDocument).toHaveBeenCalledWith( - user, - caseId, - courtId, - courtCaseNumber, - CourtDocumentFolder.CASE_DOCUMENTS, - `Skjalaskrá ${policeCaseNumber}`, - `Skjalaskrá ${policeCaseNumber}.pdf`, - 'application/pdf', - pdf, - ) - }) - }) - - describe('pdf returned from AWS S3 indictment folder', () => { + describe('pdf returned from AWS S3', () => { beforeEach(async () => { const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some error')) - mockGetObject.mockReturnValueOnce(pdf) + mockGetObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, policeCaseNumber, theCase) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourtGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourtGuards.spec.ts index e0b918dcb4c3..328109144d6c 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourtGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToCourtGuards.spec.ts @@ -1,5 +1,3 @@ -import { CanActivate } from '@nestjs/common' - import { indictmentCases } from '@island.is/judicial-system/types' import { CaseExistsGuard } from '../../guards/caseExists.guard' @@ -17,34 +15,12 @@ describe('InternalCaseController - Deliver case files record to court guards', ( ) }) - it('should have two guards', () => { + it('should have the right guard configuration', () => { expect(guards).toHaveLength(2) - }) - - describe('CaseExistsGuard', () => { - let guard: CanActivate - - beforeEach(() => { - guard = new guards[0]() - }) - - it('should have CaseExistsGuard as guard 1', () => { - expect(guard).toBeInstanceOf(CaseExistsGuard) - }) - }) - - describe('CaseTypeGuard', () => { - let guard: CanActivate - - beforeEach(() => { - guard = guards[1] - }) - - it('should have CaseTypeGuard as guard 2', () => { - expect(guard).toBeInstanceOf(CaseTypeGuard) - expect(guard).toEqual({ - allowedCaseTypes: indictmentCases, - }) + expect(new guards[0]()).toBeInstanceOf(CaseExistsGuard) + expect(guards[1]).toBeInstanceOf(CaseTypeGuard) + expect(guards[1]).toEqual({ + allowedCaseTypes: indictmentCases, }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToPolice.spec.ts index 57d1eb6f335b..860e0e59dfd1 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseFilesRecordToPolice.spec.ts @@ -11,7 +11,7 @@ import { nowFactory } from '../../../../factories' import { createCaseFilesRecord } from '../../../../formatters' import { randomDate } from '../../../../test' import { AwsS3Service } from '../../../aws-s3' -import { CourtDocumentType, PoliceService } from '../../../police' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -34,7 +34,7 @@ describe('InternalCaseController - Deliver case files record to police', () => { const user = { id: uuid() } as User const caseId = uuid() const caseType = CaseType.INDICTMENT - const caseState = CaseState.ACCEPTED + const caseState = CaseState.COMPLETED const policeCaseNumber = uuid() const defendantNationalId = '0123456789' const courtId = uuid() @@ -107,13 +107,10 @@ describe('InternalCaseController - Deliver case files record to police', () => { }) it('should update the police case', () => { - expect(mockAwsS3Service.getObject).toHaveBeenNthCalledWith( - 1, - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - expect(mockAwsS3Service.getObject).toHaveBeenNthCalledWith( - 2, - `indictments/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + caseType, + caseState, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, ) expect(createCaseFilesRecord).toHaveBeenCalledWith( theCase, @@ -122,7 +119,9 @@ describe('InternalCaseController - Deliver case files record to police', () => { expect.any(Function), ) expect(mockAwsS3Service.putObject).toHaveBeenCalledWith( - `indictments/completed/${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, + theCase.type, + theCase.state, + `${theCase.id}/${policeCaseNumber}/caseFilesRecord.pdf`, pdf.toString(), ) expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( @@ -137,7 +136,7 @@ describe('InternalCaseController - Deliver case files record to police', () => { '', [ { - type: CourtDocumentType.RVMG, + type: PoliceDocumentType.RVMG, courtDocument: Base64.btoa(pdf.toString('binary')), }, ], @@ -146,40 +145,10 @@ describe('InternalCaseController - Deliver case files record to police', () => { }) }) - describe('pdf returned from AWS S3 indictment completed folder', () => { - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockReturnValueOnce(pdf) - - await givenWhenThen(caseId, policeCaseNumber, theCase) - }) - - it('should use the AWS S3 pdf', () => { - expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( - user, - caseId, - caseType, - caseState, - policeCaseNumber, - courtCaseNumber, - defendantNationalId, - date, - '', - [ - { - type: CourtDocumentType.RVMG, - courtDocument: Base64.btoa(pdf.toString('binary')), - }, - ], - ) - }) - }) - - describe('pdf returned from AWS S3 indictment folder', () => { + describe('pdf returned from AWS S3', () => { beforeEach(async () => { const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some error')) - mockGetObject.mockReturnValueOnce(pdf) + mockGetObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, policeCaseNumber, theCase) }) @@ -197,7 +166,7 @@ describe('InternalCaseController - Deliver case files record to police', () => { '', [ { - type: CourtDocumentType.RVMG, + type: PoliceDocumentType.RVMG, courtDocument: Base64.btoa(pdf.toString('binary')), }, ], diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseToPolice.spec.ts index d26aa17ec415..65ad3532e525 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverCaseToPolice.spec.ts @@ -16,7 +16,7 @@ import { getRequestPdfAsString, } from '../../../../formatters' import { randomDate } from '../../../../test' -import { CourtDocumentType, PoliceService } from '../../../police' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -130,15 +130,15 @@ describe('InternalCaseController - Deliver case to police', () => { caseConclusion, [ { - type: CourtDocumentType.RVKR, + type: PoliceDocumentType.RVKR, courtDocument: Base64.btoa(requestPdf), }, { - type: CourtDocumentType.RVTB, + type: PoliceDocumentType.RVTB, courtDocument: Base64.btoa(courtRecordPdf), }, { - type: CourtDocumentType.RVVI, + type: PoliceDocumentType.RVVI, courtDocument: Base64.btoa(custodyNoticePdf), }, ], diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentCaseToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentCaseToPolice.spec.ts index 8bc07564f842..9897732717a4 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentCaseToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentCaseToPolice.spec.ts @@ -14,7 +14,7 @@ import { createTestingCaseModule } from '../createTestingCaseModule' import { nowFactory } from '../../../../factories' import { randomDate } from '../../../../test' import { AwsS3Service } from '../../../aws-s3' -import { CourtDocumentType, PoliceService } from '../../../police' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -101,8 +101,16 @@ describe('InternalCaseController - Deliver indictment case to police', () => { }) it('should update the police case', async () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(courtRecordKey) - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(rulingKey) + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + caseType, + caseState, + courtRecordKey, + ) + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + caseType, + caseState, + rulingKey, + ) expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( user, caseId, @@ -115,11 +123,11 @@ describe('InternalCaseController - Deliver indictment case to police', () => { '', [ { - type: CourtDocumentType.RVTB, + type: PoliceDocumentType.RVTB, courtDocument: Base64.btoa(courtRecordPdf), }, { - type: CourtDocumentType.RVDO, + type: PoliceDocumentType.RVDO, courtDocument: Base64.btoa(rulingPdf), }, ], diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourt.spec.ts new file mode 100644 index 000000000000..0bcb6dcd14ba --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourt.spec.ts @@ -0,0 +1,166 @@ +import { uuid } from 'uuidv4' + +import { + CaseState, + CaseType, + IndictmentSubtype, + User, +} from '@island.is/judicial-system/types' + +import { createTestingCaseModule } from '../createTestingCaseModule' + +import { createIndictment } from '../../../../formatters' +import { AwsS3Service } from '../../../aws-s3' +import { CourtDocumentFolder, CourtService } from '../../../court' +import { Case } from '../../models/case.model' +import { DeliverResponse } from '../../models/deliver.response' + +jest.mock('../../../../formatters/indictmentPdf') + +interface Then { + result: DeliverResponse + error: Error +} + +type GivenWhenThen = (caseId: string, theCase: Case) => Promise + +describe('InternalCaseController - Deliver indictment to court', () => { + const user = { id: uuid() } as User + const caseId = uuid() + const policeCaseNumber = uuid() + const courtId = uuid() + const courtCaseNumber = uuid() + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, + policeCaseNumbers: [policeCaseNumber], + indictmentSubtypes: { + [policeCaseNumber]: [IndictmentSubtype.TRAFFIC_VIOLATION], + }, + courtId, + courtCaseNumber, + indictmentHash: uuid(), + } as Case + const pdf = Buffer.from('test indictment') + + let mockAwsS3Service: AwsS3Service + let mockCourtService: CourtService + let givenWhenThen: GivenWhenThen + + beforeEach(async () => { + const { awsS3Service, courtService, internalCaseController } = + await createTestingCaseModule() + + mockAwsS3Service = awsS3Service + const mockGetObject = mockAwsS3Service.getObject as jest.Mock + mockGetObject.mockRejectedValue(new Error('Some error')) + + const mockCreateIndictment = createIndictment as jest.Mock + mockCreateIndictment.mockRejectedValue(new Error('Some error')) + + mockCourtService = courtService + const mockCreateDocument = mockCourtService.createDocument as jest.Mock + mockCreateDocument.mockRejectedValue(new Error('Some error')) + + givenWhenThen = async (caseId: string, theCase: Case) => { + const then = {} as Then + + await internalCaseController + .deliverIndictmentToCourt(caseId, theCase, { user }) + .then((result) => (then.result = result)) + .catch((error) => (then.error = error)) + + return then + } + }) + + describe('deliver generated indictment pdf to court', () => { + let then: Then + + beforeEach(async () => { + const mockCreateIndictment = createIndictment as jest.Mock + mockCreateIndictment.mockResolvedValueOnce(pdf) + const mockCreateDocument = mockCourtService.createDocument as jest.Mock + mockCreateDocument.mockResolvedValueOnce(uuid()) + + then = await givenWhenThen(caseId, theCase) + }) + + it('should deliver the indictment', () => { + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${theCase.id}/indictment.pdf`, + ) + expect(createIndictment).toHaveBeenCalledWith( + theCase, + expect.any(Function), + undefined, + ) + expect(mockCourtService.createDocument).toHaveBeenCalledWith( + user, + caseId, + courtId, + courtCaseNumber, + CourtDocumentFolder.INDICTMENT_DOCUMENTS, + `Ákæra`, + `Ákæra.pdf`, + 'application/pdf', + pdf, + ) + expect(then.result).toEqual({ delivered: true }) + }) + }) + + describe('deliver indictment pdf from AWS S3 to court', () => { + beforeEach(async () => { + const mockGetGeneratedIndictmentCaseObject = + mockAwsS3Service.getObject as jest.Mock + mockGetGeneratedIndictmentCaseObject.mockResolvedValueOnce(pdf) + + await givenWhenThen(caseId, theCase) + }) + + it('should use the AWS S3 pdf', () => { + expect(mockCourtService.createDocument).toHaveBeenCalledWith( + user, + caseId, + courtId, + courtCaseNumber, + CourtDocumentFolder.INDICTMENT_DOCUMENTS, + `Ákæra`, + `Ákæra.pdf`, + 'application/pdf', + pdf, + ) + }) + }) + + describe('delivery to court fails', () => { + let then: Then + + beforeEach(async () => { + const mockCreateIndictment = createIndictment as jest.Mock + mockCreateIndictment.mockResolvedValueOnce(pdf) + + then = await givenWhenThen(caseId, theCase) + }) + + it('should return a failure response', async () => { + expect(then.result.delivered).toEqual(false) + }) + }) + + describe('pdf generation fails', () => { + let then: Then + + beforeEach(async () => { + then = await givenWhenThen(caseId, theCase) + }) + + it('should return a failure response', async () => { + expect(then.result.delivered).toEqual(false) + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourtGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourtGuards.spec.ts new file mode 100644 index 000000000000..897190bc36a4 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToCourtGuards.spec.ts @@ -0,0 +1,26 @@ +import { indictmentCases } from '@island.is/judicial-system/types' + +import { CaseExistsGuard } from '../../guards/caseExists.guard' +import { CaseTypeGuard } from '../../guards/caseType.guard' +import { InternalCaseController } from '../../internalCase.controller' + +describe('InternalCaseController - Deliver indictment to court guards', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let guards: any[] + + beforeEach(() => { + guards = Reflect.getMetadata( + '__guards__', + InternalCaseController.prototype.deliverIndictmentToCourt, + ) + }) + + it('should have the right guard configuration', () => { + expect(guards).toHaveLength(2) + expect(new guards[0]()).toBeInstanceOf(CaseExistsGuard) + expect(guards[1]).toBeInstanceOf(CaseTypeGuard) + expect(guards[1]).toEqual({ + allowedCaseTypes: indictmentCases, + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPolice.spec.ts index 6eab6494afed..a9bf45ec1fb2 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPolice.spec.ts @@ -6,6 +6,7 @@ import { CaseOrigin, CaseState, CaseType, + IndictmentSubtype, User, } from '@island.is/judicial-system/types' @@ -15,7 +16,8 @@ import { nowFactory } from '../../../../factories' import { createIndictment } from '../../../../formatters' import { randomDate } from '../../../../test' import { AwsS3Service } from '../../../aws-s3' -import { CourtDocumentType, PoliceService } from '../../../police' +import { FileService } from '../../../file' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -35,20 +37,24 @@ describe('InternalCaseController - Deliver indictment to police', () => { const user = { id: userId } as User let mockAwsS3Service: AwsS3Service + let mockFileService: FileService let mockPoliceService: PoliceService let givenWhenThen: GivenWhenThen beforeEach(async () => { - const { awsS3Service, policeService, internalCaseController } = + const { awsS3Service, fileService, policeService, internalCaseController } = await createTestingCaseModule() mockAwsS3Service = awsS3Service + mockFileService = fileService mockPoliceService = policeService const mockToday = nowFactory as jest.Mock mockToday.mockReturnValueOnce(date) - const mockGetObject = awsS3Service.getObject as jest.Mock + const mockGetObject = mockAwsS3Service.getObject as jest.Mock mockGetObject.mockRejectedValue(new Error('Some error')) + const mockGetCaseFileFromS3 = mockFileService.getCaseFileFromS3 as jest.Mock + mockGetCaseFileFromS3.mockRejectedValue(new Error('Some error')) const mockCreateIndictment = createIndictment as jest.Mock mockCreateIndictment.mockRejectedValue(new Error('Some error')) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock @@ -71,12 +77,17 @@ describe('InternalCaseController - Deliver indictment to police', () => { describe('deliver indictment case files to police', () => { const caseId = uuid() const caseType = CaseType.INDICTMENT - const caseState = CaseState.ACCEPTED + const caseState = CaseState.WAITING_FOR_CONFIRMATION const policeCaseNumber = uuid() const courtCaseNumber = uuid() const defendantNationalId = '0123456789' const indictmentKey = uuid() const indictmentPdf = 'test indictment' + const caseFile = { + id: uuid(), + key: indictmentKey, + category: CaseFileCategory.INDICTMENT, + } const theCase = { id: caseId, origin: CaseOrigin.LOKE, @@ -85,16 +96,15 @@ describe('InternalCaseController - Deliver indictment to police', () => { policeCaseNumbers: [policeCaseNumber], courtCaseNumber, defendants: [{ nationalId: defendantNationalId }], - caseFiles: [ - { key: indictmentKey, category: CaseFileCategory.INDICTMENT }, - ], + caseFiles: [caseFile], } as Case let then: Then beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(indictmentPdf) + const mockGetCaseFileFromS3 = + mockFileService.getCaseFileFromS3 as jest.Mock + mockGetCaseFileFromS3.mockResolvedValueOnce(indictmentPdf) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock mockUpdatePoliceCase.mockResolvedValueOnce(true) @@ -103,7 +113,10 @@ describe('InternalCaseController - Deliver indictment to police', () => { }) it('should update the police case', async () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(indictmentKey) + expect(mockFileService.getCaseFileFromS3).toHaveBeenCalledWith( + theCase, + caseFile, + ) expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( user, caseId, @@ -116,7 +129,7 @@ describe('InternalCaseController - Deliver indictment to police', () => { '', [ { - type: CourtDocumentType.RVAS, + type: PoliceDocumentType.RVAS, courtDocument: Base64.btoa(indictmentPdf), }, ], @@ -128,7 +141,7 @@ describe('InternalCaseController - Deliver indictment to police', () => { describe('deliver generated indictment pdf to police', () => { const caseId = uuid() const caseType = CaseType.INDICTMENT - const caseState = CaseState.ACCEPTED + const caseState = CaseState.COMPLETED const policeCaseNumber = uuid() const courtCaseNumber = uuid() const defendantNationalId = '0123456789' @@ -141,6 +154,9 @@ describe('InternalCaseController - Deliver indictment to police', () => { policeCaseNumbers: [policeCaseNumber], courtCaseNumber, defendants: [{ nationalId: defendantNationalId }], + indictmentSubtypes: { + [policeCaseNumber]: [IndictmentSubtype.TRAFFIC_VIOLATION], + }, } as Case let then: Then @@ -173,7 +189,7 @@ describe('InternalCaseController - Deliver indictment to police', () => { '', [ { - type: CourtDocumentType.RVAS, + type: PoliceDocumentType.RVAS, courtDocument: Base64.btoa(indictmentPdf), }, ], @@ -181,4 +197,55 @@ describe('InternalCaseController - Deliver indictment to police', () => { expect(then.result.delivered).toEqual(true) }) }) + + describe('deliver indictment pdf from AWS S3 to police', () => { + const caseId = uuid() + const caseType = CaseType.INDICTMENT + const caseState = CaseState.COMPLETED + const policeCaseNumber = uuid() + const courtCaseNumber = uuid() + const defendantNationalId = '0123456789' + const indictmentPdf = 'test indictment' + const theCase = { + id: caseId, + origin: CaseOrigin.LOKE, + type: caseType, + state: caseState, + policeCaseNumbers: [policeCaseNumber], + courtCaseNumber, + defendants: [{ nationalId: defendantNationalId }], + indictmentSubtypes: { + [policeCaseNumber]: [IndictmentSubtype.TRAFFIC_VIOLATION], + }, + indictmentHash: uuid(), + } as Case + + beforeEach(async () => { + const mockGetGeneratedIndictmentCaseObject = + mockAwsS3Service.getObject as jest.Mock + mockGetGeneratedIndictmentCaseObject.mockResolvedValueOnce(indictmentPdf) + + await givenWhenThen(caseId, theCase) + }) + + it('should update the police case', async () => { + expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( + user, + caseId, + caseType, + caseState, + policeCaseNumber, + courtCaseNumber, + defendantNationalId, + date, + '', + [ + { + type: PoliceDocumentType.RVAS, + courtDocument: Base64.btoa(indictmentPdf), + }, + ], + ) + }) + }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPoliceGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPoliceGuards.spec.ts index 3d389c82009d..454c56553c2b 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPoliceGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentToPoliceGuards.spec.ts @@ -1,5 +1,3 @@ -import { CanActivate } from '@nestjs/common' - import { indictmentCases } from '@island.is/judicial-system/types' import { CaseExistsGuard } from '../../guards/caseExists.guard' @@ -17,34 +15,12 @@ describe('InternalCaseController - Deliver indictment to police guards', () => { ) }) - it('should have two guards', () => { + it('should have the right guard configuration', () => { expect(guards).toHaveLength(2) - }) - - describe('CaseExistsGuard', () => { - let guard: CanActivate - - beforeEach(() => { - guard = new guards[0]() - }) - - it('should have CaseExistsGuard as guard 1', () => { - expect(guard).toBeInstanceOf(CaseExistsGuard) - }) - }) - - describe('CaseTypeGuard', () => { - let guard: CanActivate - - beforeEach(() => { - guard = guards[1] - }) - - it('should have CaseTypeGuard as guard 2', () => { - expect(guard).toBeInstanceOf(CaseTypeGuard) - expect(guard).toEqual({ - allowedCaseTypes: indictmentCases, - }) + expect(new guards[0]()).toBeInstanceOf(CaseExistsGuard) + expect(guards[1]).toBeInstanceOf(CaseTypeGuard) + expect(guards[1]).toEqual({ + allowedCaseTypes: indictmentCases, }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToCourt.spec.ts index 30df480ec2c0..b0d1b3e91c19 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToCourt.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToCourt.spec.ts @@ -1,7 +1,7 @@ import format from 'date-fns/format' import { uuid } from 'uuidv4' -import { User } from '@island.is/judicial-system/types' +import { CaseState, CaseType, User } from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -38,8 +38,9 @@ describe('InternalCaseController - Deliver signed ruling to court', () => { mockCreateDocument.mockRejectedValue(new Error('Some error')) mockAwsS3Service = awsS3Service - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValue(new Error('Some error')) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async (caseId: string, theCase: Case) => { const then = {} as Then @@ -56,8 +57,17 @@ describe('InternalCaseController - Deliver signed ruling to court', () => { describe('signed ruling delivered', () => { const caseId = uuid() const courtId = uuid() + const caseType = CaseType.BODY_SEARCH + const caseState = CaseState.ACCEPTED + const courtCaseNumber = uuid() - const theCase = { id: caseId, courtId, courtCaseNumber } as Case + const theCase = { + id: caseId, + type: caseType, + state: caseState, + courtId, + courtCaseNumber, + } as Case const pdf = Buffer.from('test ruling') const now = randomDate() @@ -66,21 +76,20 @@ describe('InternalCaseController - Deliver signed ruling to court', () => { beforeEach(async () => { const mockNowFactory = nowFactory as jest.Mock mockNowFactory.mockReturnValue(now) - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) const mockCreateDocument = mockCourtService.createDocument as jest.Mock mockCreateDocument.mockResolvedValueOnce(uuid()) then = await givenWhenThen(caseId, theCase) }) - it('should get the signed ruling from S3', async () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/ruling.pdf`, + it('should deliver the signed ruling to court', async () => { + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/ruling.pdf`, ) - }) - - it('should create a ruling at court', async () => { expect(mockCourtService.createDocument).toHaveBeenCalledWith( user, caseId, @@ -92,9 +101,6 @@ describe('InternalCaseController - Deliver signed ruling to court', () => { 'application/pdf', pdf, ) - }) - - it('should return a success response', async () => { expect(then.result.delivered).toEqual(true) }) }) @@ -108,8 +114,9 @@ describe('InternalCaseController - Deliver signed ruling to court', () => { let then: Then beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) then = await givenWhenThen(caseId, theCase) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToPolice.spec.ts index bfc2c4634e90..6085395e9d23 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToPolice.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedRulingToPolice.spec.ts @@ -12,7 +12,7 @@ import { createTestingCaseModule } from '../createTestingCaseModule' import { randomDate } from '../../../../test' import { AwsS3Service } from '../../../aws-s3' -import { CourtDocumentType, PoliceService } from '../../../police' +import { PoliceDocumentType, PoliceService } from '../../../police' import { Case } from '../../models/case.model' import { DeliverResponse } from '../../models/deliver.response' @@ -38,8 +38,8 @@ describe('InternalCaseController - Deliver signed ruling to police', () => { mockAwsS3Service = awsS3Service mockPoliceService = policeService - const mockGetObject = awsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValue(new Error('Some error')) + const mockGetGeneratedObject = awsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock mockUpdatePoliceCase.mockRejectedValue(new Error('Some error')) @@ -80,8 +80,9 @@ describe('InternalCaseController - Deliver signed ruling to police', () => { let then: Then beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(rulingPdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(rulingPdf) const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock mockUpdatePoliceCase.mockResolvedValueOnce(true) @@ -90,8 +91,9 @@ describe('InternalCaseController - Deliver signed ruling to police', () => { }) it('should update the police case', async () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/ruling.pdf`, + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/ruling.pdf`, ) expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( user, @@ -105,7 +107,7 @@ describe('InternalCaseController - Deliver signed ruling to police', () => { caseConclusion, [ { - type: CourtDocumentType.RVUR, + type: PoliceDocumentType.RVUR, courtDocument: Base64.btoa(rulingPdf), }, ], diff --git a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCaseFilesRecordPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCaseFilesRecordPdf.spec.ts index 6690c916730c..5a8fbdb69ce0 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCaseFilesRecordPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCaseFilesRecordPdf.spec.ts @@ -3,7 +3,11 @@ import { uuid } from 'uuidv4' import { BadRequestException } from '@nestjs/common' -import { CaseFileCategory, CaseState } from '@island.is/judicial-system/types' +import { + CaseFileCategory, + CaseState, + CaseType, +} from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -38,11 +42,12 @@ describe('LimitedAccessCaseController - Get case files record pdf', () => { ] as CaseFile[] const theCase = { id: caseId, - state: CaseState.ACCEPTED, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, policeCaseNumbers: [uuid(), policeCaseNumber, uuid()], caseFiles, } as Case - const pdf = uuid() + const pdf = Buffer.from(uuid()) const res = { end: jest.fn() } as unknown as Response let mockawsS3Service: AwsS3Service @@ -55,6 +60,8 @@ describe('LimitedAccessCaseController - Get case files record pdf', () => { mockawsS3Service = awsS3Service const mockGetObject = mockawsS3Service.getObject as jest.Mock mockGetObject.mockRejectedValue(new Error('Some error')) + const mockPutObject = mockawsS3Service.putObject as jest.Mock + mockPutObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async (policeCaseNumber: string) => { const then = {} as Then @@ -83,13 +90,10 @@ describe('LimitedAccessCaseController - Get case files record pdf', () => { }) it('should generate pdf after failing to get it from AWS S3', () => { - expect(mockawsS3Service.getObject).toHaveBeenNthCalledWith( - 1, - `indictments/completed/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, - ) - expect(mockawsS3Service.getObject).toHaveBeenNthCalledWith( - 2, - `indictments/${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, + expect(mockawsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, ) expect(createCaseFilesRecord).toHaveBeenCalledWith( theCase, @@ -97,28 +101,20 @@ describe('LimitedAccessCaseController - Get case files record pdf', () => { expect.any(Array), expect.any(Function), ) + expect(mockawsS3Service.putObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/${policeCaseNumber}/caseFilesRecord.pdf`, + pdf.toString('binary'), + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) - describe('pdf returned from AWS S3 indictment completed folder', () => { - beforeEach(async () => { - const mockGetObject = mockawsS3Service.getObject as jest.Mock - mockGetObject.mockReturnValueOnce(pdf) - - await givenWhenThen(policeCaseNumber) - }) - - it('should return pdf', () => { - expect(res.end).toHaveBeenCalledWith(pdf) - }) - }) - - describe('pdf returned from AWS S3 indictment folder', () => { + describe('pdf returned from AWS S3', () => { beforeEach(async () => { const mockGetObject = mockawsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some error')) - mockGetObject.mockReturnValueOnce(pdf) + mockGetObject.mockResolvedValueOnce(pdf) await givenWhenThen(policeCaseNumber) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCourtRecordPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCourtRecordPdf.spec.ts index d624584fd8ea..2d642cd9d34a 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCourtRecordPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getCourtRecordPdf.spec.ts @@ -3,7 +3,7 @@ import { uuid } from 'uuidv4' import { Logger } from '@island.is/logging' -import { User } from '@island.is/judicial-system/types' +import { CaseState, CaseType, User } from '@island.is/judicial-system/types' import { createTestingCaseModule } from '../createTestingCaseModule' @@ -33,9 +33,16 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { beforeEach(async () => { const { awsS3Service, logger, limitedAccessCaseController } = await createTestingCaseModule() + mockAwsS3Service = awsS3Service mockLogger = logger + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) + const getMock = getCourtRecordPdfAsBuffer as jest.Mock + getMock.mockRejectedValue(new Error('Some error')) + givenWhenThen = async ( caseId: string, user: User, @@ -59,44 +66,33 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { } }) - describe('AWS S3 lookup', () => { - const user = {} as User - const caseId = uuid() - const theCase = { - id: caseId, - courtRecordSignatureDate: nowFactory(), - } as Case - const res = {} as Response - - beforeEach(async () => { - await givenWhenThen(caseId, user, theCase, res) - }) - - it('should lookup pdf', () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/courtRecord.pdf`, - ) - }) - }) - describe('AWS S3 pdf returned', () => { const user = {} as User const caseId = uuid() + const caseType = CaseType.EXPULSION_FROM_HOME + const caseState = CaseState.DISMISSED const theCase = { id: caseId, + type: caseType, + state: caseState, courtRecordSignatureDate: nowFactory(), } as Case const res = { end: jest.fn() } as unknown as Response const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, user, theCase, res) }) it('should return pdf', () => { + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/courtRecord.pdf`, + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -109,12 +105,9 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { courtRecordSignatureDate: nowFactory(), } as Case const res = {} as Response - const error = new Error('Some ignored error') + const error = new Error('Some error') beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(error) - await givenWhenThen(caseId, user, theCase, res) }) @@ -126,31 +119,6 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { }) }) - describe('pdf generated', () => { - const user = {} as User - const caseId = uuid() - const theCase = { - id: caseId, - courtRecordSignatureDate: nowFactory(), - } as Case - const res = {} as Response - - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - - await givenWhenThen(caseId, user, theCase, res) - }) - - it('should generate pdf', () => { - expect(getCourtRecordPdfAsBuffer).toHaveBeenCalledWith( - theCase, - expect.any(Function), - user, - ) - }) - }) - describe('generated pdf returned', () => { const user = {} as User const caseId = uuid() @@ -162,8 +130,6 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) const getMock = getCourtRecordPdfAsBuffer as jest.Mock getMock.mockResolvedValueOnce(pdf) @@ -171,6 +137,11 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { }) it('should return pdf', () => { + expect(getCourtRecordPdfAsBuffer).toHaveBeenCalledWith( + theCase, + expect.any(Function), + user, + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -186,11 +157,6 @@ describe('LimitedAccessCaseController - Get court record pdf', () => { const res = {} as Response beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - const getMock = getCourtRecordPdfAsBuffer as jest.Mock - getMock.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, user, theCase, res) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getIndictmentPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getIndictmentPdf.spec.ts index 6e40f0b0e114..026b70c71758 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getIndictmentPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getIndictmentPdf.spec.ts @@ -1,9 +1,16 @@ import { Response } from 'express' import { uuid } from 'uuidv4' +import { + CaseState, + CaseType, + IndictmentSubtype, +} from '@island.is/judicial-system/types' + import { createTestingCaseModule } from '../createTestingCaseModule' import { createIndictment } from '../../../../formatters' +import { AwsS3Service } from '../../../aws-s3' import { Case } from '../../models/case.model' jest.mock('../../../../formatters/indictmentPdf') @@ -16,16 +23,30 @@ type GivenWhenThen = () => Promise describe('LimitedCaseController - Get indictment pdf', () => { const caseId = uuid() + const policeCaseNumber = uuid() const theCase = { id: caseId, + type: CaseType.INDICTMENT, + state: CaseState.COMPLETED, + policeCaseNumbers: [policeCaseNumber], + indictmentSubtypes: { + [policeCaseNumber]: [IndictmentSubtype.TRAFFIC_VIOLATION], + }, + indictmentHash: uuid(), } as Case - const pdf = uuid() + const pdf = Buffer.from(uuid()) const res = { end: jest.fn() } as unknown as Response + let mockawsS3Service: AwsS3Service let givenWhenThen: GivenWhenThen beforeEach(async () => { - const { limitedAccessCaseController } = await createTestingCaseModule() + const { awsS3Service, limitedAccessCaseController } = + await createTestingCaseModule() + + mockawsS3Service = awsS3Service + const mockGetObject = mockawsS3Service.getObject as jest.Mock + mockGetObject.mockRejectedValue(new Error('Some error')) givenWhenThen = async () => { const then = {} as Then @@ -49,6 +70,11 @@ describe('LimitedCaseController - Get indictment pdf', () => { }) it('should generate pdf', () => { + expect(mockawsS3Service.getObject).toHaveBeenCalledWith( + theCase.type, + theCase.state, + `${caseId}/indictment.pdf`, + ) expect(createIndictment).toHaveBeenCalledWith( theCase, expect.any(Function), @@ -57,4 +83,17 @@ describe('LimitedCaseController - Get indictment pdf', () => { expect(res.end).toHaveBeenCalledWith(pdf) }) }) + + describe('pdf returned from AWS S3', () => { + beforeEach(async () => { + const mockGetObject = mockawsS3Service.getObject as jest.Mock + mockGetObject.mockResolvedValueOnce(pdf) + + await givenWhenThen() + }) + + it('should return pdf', () => { + expect(res.end).toHaveBeenCalledWith(pdf) + }) + }) }) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getRulingPdf.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getRulingPdf.spec.ts index 3b19de1e2299..d7e5b8e6c89c 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getRulingPdf.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/limitedAccessCaseController/getRulingPdf.spec.ts @@ -3,6 +3,8 @@ import { uuid } from 'uuidv4' import { Logger } from '@island.is/logging' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingCaseModule } from '../createTestingCaseModule' import { nowFactory } from '../../../../factories' @@ -30,9 +32,16 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { beforeEach(async () => { const { awsS3Service, logger, limitedAccessCaseController } = await createTestingCaseModule() + mockAwsS3Service = awsS3Service mockLogger = logger + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) + const getMock = getRulingPdfAsBuffer as jest.Mock + getMock.mockRejectedValue(new Error('Some error')) + givenWhenThen = async (caseId: string, theCase: Case, res: Response) => { const then = {} as Then @@ -46,36 +55,32 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { } }) - describe('AWS S3 lookup', () => { - const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = {} as Response - - beforeEach(async () => { - await givenWhenThen(caseId, theCase, res) - }) - - it('should lookup pdf', () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( - `generated/${caseId}/ruling.pdf`, - ) - }) - }) - describe('AWS S3 pdf returned', () => { const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case + const caseType = CaseType.AUTOPSY + const caseState = CaseState.REJECTED + const theCase = { + id: caseId, + type: caseType, + state: caseState, + rulingSignatureDate: nowFactory(), + } as Case const res = { end: jest.fn() } as unknown as Response const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockResolvedValueOnce(pdf) + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(pdf) await givenWhenThen(caseId, theCase, res) }) it('should return pdf', () => { + expect(mockAwsS3Service.getGeneratedObject).toHaveBeenCalledWith( + caseType, + `${caseId}/ruling.pdf`, + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -84,12 +89,9 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { const caseId = uuid() const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case const res = {} as Response - const error = new Error('Some ignored error') + const error = new Error('Some error') beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(error) - await givenWhenThen(caseId, theCase, res) }) @@ -101,26 +103,6 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { }) }) - describe('pdf generated', () => { - const caseId = uuid() - const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case - const res = {} as Response - - beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - - await givenWhenThen(caseId, theCase, res) - }) - - it('should generate pdf', () => { - expect(getRulingPdfAsBuffer).toHaveBeenCalledWith( - theCase, - expect.any(Function), - ) - }) - }) - describe('generated pdf returned', () => { const caseId = uuid() const theCase = { id: caseId, rulingSignatureDate: nowFactory() } as Case @@ -128,8 +110,6 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { const pdf = {} beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) const getMock = getRulingPdfAsBuffer as jest.Mock getMock.mockResolvedValueOnce(pdf) @@ -137,6 +117,10 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { }) it('should return pdf', () => { + expect(getRulingPdfAsBuffer).toHaveBeenCalledWith( + theCase, + expect.any(Function), + ) expect(res.end).toHaveBeenCalledWith(pdf) }) }) @@ -148,11 +132,6 @@ describe('LimitedAccessCaseController - Get ruling pdf', () => { const res = {} as Response beforeEach(async () => { - const mockGetObject = mockAwsS3Service.getObject as jest.Mock - mockGetObject.mockRejectedValueOnce(new Error('Some ignored error')) - const getMock = getRulingPdfAsBuffer as jest.Mock - getMock.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, theCase, res) }) diff --git a/apps/judicial-system/backend/src/app/modules/event-log/eventLog.service.ts b/apps/judicial-system/backend/src/app/modules/event-log/eventLog.service.ts index 044af37f6c89..c1ee4450f943 100644 --- a/apps/judicial-system/backend/src/app/modules/event-log/eventLog.service.ts +++ b/apps/judicial-system/backend/src/app/modules/event-log/eventLog.service.ts @@ -1,3 +1,4 @@ +import { Transaction } from 'sequelize/types' import { Sequelize } from 'sequelize-typescript' import { Inject, Injectable } from '@nestjs/common' @@ -11,11 +12,12 @@ import { EventType } from '@island.is/judicial-system/types' import { CreateEventLogDto } from './dto/createEventLog.dto' import { EventLog } from './models/eventLog.model' -const allowMultiple = [ - 'LOGIN', - 'LOGIN_UNAUTHORIZED', - 'LOGIN_BYPASS', - 'LOGIN_BYPASS_UNAUTHORIZED', +const allowMultiple: EventType[] = [ + EventType.LOGIN, + EventType.LOGIN_UNAUTHORIZED, + EventType.LOGIN_BYPASS, + EventType.LOGIN_BYPASS_UNAUTHORIZED, + EventType.INDICTMENT_CONFIRMED, ] @Injectable() @@ -27,7 +29,10 @@ export class EventLogService { private readonly logger: Logger, ) {} - async create(event: CreateEventLogDto): Promise { + async create( + event: CreateEventLogDto, + transaction?: Transaction, + ): Promise { const { eventType, caseId, userRole, nationalId } = event if (!allowMultiple.includes(event.eventType)) { @@ -45,28 +50,16 @@ export class EventLogService { } try { - await this.eventLogModel.create({ - eventType, - caseId, - nationalId, - userRole, - }) + await this.eventLogModel.create( + { eventType, caseId, nationalId, userRole }, + { transaction }, + ) } catch (error) { // Tolerate failure but log error this.logger.error('Failed to create event log', error) } } - async findEventTypeByCaseId(eventType: EventType, caseId: string) { - return this.eventLogModel.findOne({ - where: { - eventType, - caseId, - }, - order: [['created', 'DESC']], - }) - } - async loginMap( nationalIds: string[], ): Promise> { diff --git a/apps/judicial-system/backend/src/app/modules/file/file.controller.ts b/apps/judicial-system/backend/src/app/modules/file/file.controller.ts index c44a97392ed2..f507d84863e2 100644 --- a/apps/judicial-system/backend/src/app/modules/file/file.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/file/file.controller.ts @@ -177,12 +177,13 @@ export class FileController { }) deleteCaseFile( @Param('caseId') caseId: string, + @CurrentCase() theCase: Case, @Param('fileId') fileId: string, @CurrentCaseFile() caseFile: CaseFile, ): Promise { this.logger.debug(`Deleting file ${fileId} of case ${caseId}`) - return this.fileService.deleteCaseFile(caseFile) + return this.fileService.deleteCaseFile(theCase, caseFile) } @UseGuards( @@ -208,7 +209,7 @@ export class FileController { ): Promise { this.logger.debug(`Uploading file ${fileId} of case ${caseId} to court`) - return this.fileService.uploadCaseFileToCourt(caseFile, theCase, user) + return this.fileService.uploadCaseFileToCourt(theCase, caseFile, user) } @UseGuards( diff --git a/apps/judicial-system/backend/src/app/modules/file/file.module.ts b/apps/judicial-system/backend/src/app/modules/file/file.module.ts index b76ea0352f28..54956e763846 100644 --- a/apps/judicial-system/backend/src/app/modules/file/file.module.ts +++ b/apps/judicial-system/backend/src/app/modules/file/file.module.ts @@ -5,7 +5,7 @@ import { CmsTranslationsModule } from '@island.is/cms-translations' import { MessageModule } from '@island.is/judicial-system/message' -import { AwsS3Module, CaseModule, CourtModule } from '../index' +import { AwsS3Module, CaseModule, CourtModule, UserModule } from '../index' import { CaseFile } from './models/file.model' import { FileController } from './file.controller' import { FileService } from './file.service' @@ -16,6 +16,7 @@ import { LimitedAccessFileController } from './limitedAccessFile.controller' imports: [ CmsTranslationsModule, MessageModule, + forwardRef(() => UserModule), forwardRef(() => CaseModule), forwardRef(() => CourtModule), forwardRef(() => AwsS3Module), diff --git a/apps/judicial-system/backend/src/app/modules/file/file.service.ts b/apps/judicial-system/backend/src/app/modules/file/file.service.ts index 804511ac1d3b..870565dcef16 100644 --- a/apps/judicial-system/backend/src/app/modules/file/file.service.ts +++ b/apps/judicial-system/backend/src/app/modules/file/file.service.ts @@ -1,3 +1,4 @@ +import CryptoJS from 'crypto-js' import { Op, Sequelize } from 'sequelize' import { Transaction } from 'sequelize/types' import { uuid } from 'uuidv4' @@ -20,15 +21,16 @@ import type { User } from '@island.is/judicial-system/types' import { CaseFileCategory, CaseFileState, - CaseState, - completedIndictmentCaseStates, + EventType, + hasIndictmentCaseBeenSubmittedToCourt, isIndictmentCase, } from '@island.is/judicial-system/types' -import { formatConfirmedIndictmentKey } from '../../formatters/formatters' +import { createConfirmedIndictment } from '../../formatters' import { AwsS3Service } from '../aws-s3' import { Case } from '../case' import { CourtDocumentFolder, CourtService } from '../court' +import { UserService } from '../user' import { CreateFileDto } from './dto/createFile.dto' import { CreatePresignedPostDto } from './dto/createPresignedPost.dto' import { UpdateFileDto } from './dto/updateFile.dto' @@ -40,13 +42,10 @@ import { SignedUrl } from './models/signedUrl.model' import { UploadFileToCourtResponse } from './models/uploadFileToCourt.response' import { fileModuleConfig } from './file.config' -// Files are stored in AWS S3 under a key which has the following formats: -// uploads/// for restriction and investigation cases +// File keys have the following format: +// // // As uuid-s have length 36, the filename starts at position 82 in the key. -const NAME_BEGINS_INDEX = 82 -// indictments/// for indictment cases -// As uuid-s have length 36, the filename starts at position 82 in the key. -const INDICTMENT_NAME_BEGINS_INDEX = 86 +const NAME_BEGINS_INDEX = 74 @Injectable() export class FileService { @@ -55,6 +54,7 @@ export class FileService { constructor( @InjectConnection() private readonly sequelize: Sequelize, @InjectModel(CaseFile) private readonly fileModel: typeof CaseFile, + private readonly userService: UserService, private readonly courtService: CourtService, private readonly awsS3Service: AwsS3Service, private readonly messageService: MessageService, @@ -91,22 +91,27 @@ export class FileService { return numberOfAffectedRows > 0 } - private async tryDeleteFileFromS3(file: CaseFile): Promise { + private async tryDeleteFileFromS3( + theCase: Case, + file: CaseFile, + ): Promise { this.logger.debug(`Attempting to delete file ${file.key} from AWS S3`) if (!file.key) { return true } - return this.awsS3Service.deleteObject(file.key).catch((reason) => { - // Tolerate failure, but log what happened - this.logger.error( - `Could not delete file ${file.id} of case ${file.caseId} from AWS S3`, - { reason }, - ) + return this.awsS3Service + .deleteObject(theCase.type, theCase.state, file.key) + .catch((reason) => { + // Tolerate failure, but log what happened + this.logger.error( + `Could not delete file ${file.id} of case ${file.caseId} from AWS S3`, + { reason }, + ) - return false - }) + return false + }) } private getCourtDocumentFolder(file: CaseFile) { @@ -144,6 +149,67 @@ export class FileService { return courtDocumentFolder } + private async confirmIndictmentCaseFile( + theCase: Case, + pdf: Buffer, + ): Promise { + const confirmationEvent = theCase.eventLogs?.find( + (event) => event.eventType === EventType.INDICTMENT_CONFIRMED, + ) + + if (!confirmationEvent || !confirmationEvent.nationalId) { + return undefined + } + + return this.userService + .findByNationalId(confirmationEvent.nationalId) + .then((user) => + createConfirmedIndictment( + { + actor: user.name, + institution: user.institution?.name ?? '', + date: confirmationEvent.created, + }, + pdf, + ), + ) + .then((confirmedPdf) => { + const binaryPdf = confirmedPdf.toString('binary') + const hash = CryptoJS.MD5(binaryPdf).toString(CryptoJS.enc.Hex) + + // No need to wait for the update to finish + this.fileModel.update({ hash }, { where: { id: theCase.id } }) + + return binaryPdf + }) + .catch((reason) => { + this.logger.error( + `Failed to create confirmed indictment for case ${theCase.id}`, + { reason }, + ) + + return undefined + }) + } + + async getCaseFileFromS3(theCase: Case, file: CaseFile): Promise { + if ( + isIndictmentCase(theCase.type) && + hasIndictmentCaseBeenSubmittedToCourt(theCase.state) && + file.category === CaseFileCategory.INDICTMENT + ) { + return this.awsS3Service.getConfirmedObject( + theCase.type, + theCase.state, + file.key, + !file.hash, + (content: Buffer) => this.confirmIndictmentCaseFile(theCase, content), + ) + } + + return this.awsS3Service.getObject(theCase.type, theCase.state, file.key) + } + private async throttleUpload( file: CaseFile, theCase: Case, @@ -154,7 +220,7 @@ export class FileService { this.logger.info('Previous upload failed', { reason }) }) - const content = await this.awsS3Service.getObject(file.key ?? '') + const content = await this.getCaseFileFromS3(theCase, file) const courtDocumentFolder = this.getCourtDocumentFolder(file) @@ -191,12 +257,14 @@ export class FileService { ): Promise { const { fileName, type } = createPresignedPost - return this.awsS3Service.createPresignedPost( - `${isIndictmentCase(theCase.type) ? 'indictments' : 'uploads'}/${ - theCase.id - }/${uuid()}/${fileName}`, - type, - ) + const key = `${theCase.id}/${uuid()}/${fileName}` + + return this.awsS3Service + .createPresignedPost(theCase.type, theCase.state, key, type) + .then((presignedPost) => ({ + ...presignedPost, + key, + })) } async createCaseFile( @@ -206,11 +274,7 @@ export class FileService { ): Promise { const { key } = createFile - const regExp = new RegExp( - `^${isIndictmentCase(theCase.type) ? 'indictments' : 'uploads'}/${ - theCase.id - }/.{36}/(.*)$`, - ) + const regExp = new RegExp(`^${theCase.id}/.{36}/(.*)$`) if (!regExp.test(key)) { throw new BadRequestException( @@ -218,11 +282,7 @@ export class FileService { ) } - const fileName = createFile.key.slice( - isIndictmentCase(theCase.type) - ? INDICTMENT_NAME_BEGINS_INDEX - : NAME_BEGINS_INDEX, - ) + const fileName = createFile.key.slice(NAME_BEGINS_INDEX) const file = await this.fileModel.create({ ...createFile, @@ -256,29 +316,16 @@ export class FileService { return file } - async getCaseFileSignedUrl( - theCase: Case, - file: CaseFile, - ): Promise { + private async verifyCaseFile(file: CaseFile, theCase: Case) { if (!file.key) { throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) } - let key = file.key - - if ( - file.category === CaseFileCategory.INDICTMENT && - [ - CaseState.SUBMITTED, - CaseState.RECEIVED, - CaseState.MAIN_HEARING, - ...completedIndictmentCaseStates, - ].includes(theCase.state) - ) { - key = formatConfirmedIndictmentKey(key) - } - - const exists = await this.awsS3Service.objectExists(key) + const exists = await this.awsS3Service.objectExists( + theCase.type, + theCase.state, + file.key, + ) if (!exists) { // Fire and forget, no need to wait for the result @@ -286,11 +333,49 @@ export class FileService { throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) } + } + + private async getCaseFileSignedUrlFromS3( + theCase: Case, + file: CaseFile, + timeToLive?: number, + ): Promise { + if ( + isIndictmentCase(theCase.type) && + hasIndictmentCaseBeenSubmittedToCourt(theCase.state) && + file.category === CaseFileCategory.INDICTMENT + ) { + return this.awsS3Service.getConfirmedSignedUrl( + theCase.type, + theCase.state, + file.key, + !file.hash, + (content: Buffer) => this.confirmIndictmentCaseFile(theCase, content), + timeToLive, + ) + } - return this.awsS3Service.getSignedUrl(key).then((url) => ({ url })) + return this.awsS3Service.getSignedUrl( + theCase.type, + theCase.state, + file.key, + timeToLive, + ) + } + + async getCaseFileSignedUrl( + theCase: Case, + file: CaseFile, + ): Promise { + await this.verifyCaseFile(file, theCase) + + return this.getCaseFileSignedUrlFromS3(theCase, file).then((url) => ({ + url, + })) } async deleteCaseFile( + theCase: Case, file: CaseFile, transaction?: Transaction, ): Promise { @@ -298,33 +383,22 @@ export class FileService { if (success) { // Fire and forget, no need to wait for the result - this.tryDeleteFileFromS3(file) + this.tryDeleteFileFromS3(theCase, file) } return { success } } async uploadCaseFileToCourt( - file: CaseFile, theCase: Case, + file: CaseFile, user: User, ): Promise { if (file.state === CaseFileState.STORED_IN_COURT) { return { success: true } } - if (!file.key) { - throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) - } - - const exists = await this.awsS3Service.objectExists(file.key) - - if (!exists) { - // Fire and forget, no need to wait for the result - this.fileModel.update({ key: null }, { where: { id: file.id } }) - - throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) - } + await this.verifyCaseFile(file, theCase) this.throttle = this.throttleUpload(file, theCase, user) @@ -404,47 +478,13 @@ export class FileService { } async archive(theCase: Case, file: CaseFile): Promise { - if ( - !file.key || - !file.key.startsWith('indictments/') || - file.key.startsWith('indictments/completed/') - ) { + if (!file.key) { return true } return this.awsS3Service - .copyObject( - file.key, - file.key.replace('indictments/', 'indictments/completed/'), - ) - .then((newKey) => - this.fileModel.update({ key: newKey }, { where: { id: file.id } }), - ) - .then(async () => { - if ( - file.category === CaseFileCategory.INDICTMENT && - [ - CaseState.SUBMITTED, - CaseState.RECEIVED, - CaseState.MAIN_HEARING, - ...completedIndictmentCaseStates, - ].includes(theCase.state) - ) { - return this.awsS3Service.copyObject( - formatConfirmedIndictmentKey(file.key), - formatConfirmedIndictmentKey(file.key).replace( - 'indictments/', - 'indictments/completed/', - ) ?? '', - ) - } - }) - .then(() => { - // Fire and forget, no need to wait for the result - this.tryDeleteFileFromS3(file) - - return true - }) + .archiveObject(theCase.type, theCase.state, file.key) + .then(() => true) .catch((reason) => { this.logger.error( `Failed to archive file ${file.id} of case ${file.caseId}`, @@ -455,33 +495,30 @@ export class FileService { }) } - async resetCaseFileStates(caseId: string, transaction: Transaction) { - await this.fileModel.update( + resetCaseFileStates(caseId: string, transaction: Transaction) { + return this.fileModel.update( { state: CaseFileState.STORED_IN_RVG }, { where: { caseId, state: CaseFileState.STORED_IN_COURT }, transaction }, ) } + resetIndictmentCaseFileHashes(caseId: string, transaction: Transaction) { + return this.fileModel.update( + { hash: null }, + { where: { caseId, category: CaseFileCategory.INDICTMENT }, transaction }, + ) + } + async deliverCaseFileToCourtOfAppeals( - file: CaseFile, theCase: Case, + file: CaseFile, user: User, ): Promise { - if (!file.key) { - throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) - } - - const exists = await this.awsS3Service.objectExists(file.key) - - if (!exists) { - // Fire and forget, no need to wait for the result - this.fileModel.update({ key: null }, { where: { id: file.id } }) - - throw new NotFoundException(`File ${file.id} does not exist in AWS S3`) - } + await this.verifyCaseFile(file, theCase) - const url = await this.awsS3Service.getSignedUrl( - file.key ?? '', + const url = await this.getCaseFileSignedUrlFromS3( + theCase, + file, this.config.robotS3TimeToLiveGet, ) diff --git a/apps/judicial-system/backend/src/app/modules/file/internalFile.controller.ts b/apps/judicial-system/backend/src/app/modules/file/internalFile.controller.ts index c677eb2fc68c..964929db474f 100644 --- a/apps/judicial-system/backend/src/app/modules/file/internalFile.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/file/internalFile.controller.ts @@ -57,8 +57,8 @@ export class InternalFileController { this.logger.debug(`Delivering file ${fileId} of case ${caseId} to court`) const { success } = await this.fileService.uploadCaseFileToCourt( - caseFile, theCase, + caseFile, deliverDto.user, ) @@ -110,8 +110,8 @@ export class InternalFileController { ) return this.fileService.deliverCaseFileToCourtOfAppeals( - caseFile, theCase, + caseFile, deliverDto.user, ) } diff --git a/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts b/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts index c729ee60ef19..f62585f7be9f 100644 --- a/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts @@ -137,11 +137,12 @@ export class LimitedAccessFileController { }) deleteCaseFile( @Param('caseId') caseId: string, + @CurrentCase() theCase: Case, @Param('fileId') fileId: string, @CurrentCaseFile() caseFile: CaseFile, ): Promise { this.logger.debug(`Deleting file ${fileId} of case ${caseId}`) - return this.fileService.deleteCaseFile(caseFile) + return this.fileService.deleteCaseFile(theCase, caseFile) } } diff --git a/apps/judicial-system/backend/src/app/modules/file/models/file.model.ts b/apps/judicial-system/backend/src/app/modules/file/models/file.model.ts index d3e52c73ecd4..d144598e1122 100644 --- a/apps/judicial-system/backend/src/app/modules/file/models/file.model.ts +++ b/apps/judicial-system/backend/src/app/modules/file/models/file.model.ts @@ -100,4 +100,8 @@ export class CaseFile extends Model { @Column({ type: DataType.STRING, allowNull: true }) @ApiPropertyOptional({ type: String }) policeFileId?: string + + @Column({ type: DataType.STRING, allowNull: true }) + @ApiPropertyOptional({ type: String }) + hash?: string } diff --git a/apps/judicial-system/backend/src/app/modules/file/models/presignedPost.model.ts b/apps/judicial-system/backend/src/app/modules/file/models/presignedPost.model.ts index 20335561b415..5374ba70034d 100644 --- a/apps/judicial-system/backend/src/app/modules/file/models/presignedPost.model.ts +++ b/apps/judicial-system/backend/src/app/modules/file/models/presignedPost.model.ts @@ -6,4 +6,7 @@ export class PresignedPost { @ApiProperty({ type: Object }) fields!: { [key: string]: string } + + @ApiProperty({ type: String }) + key!: string } diff --git a/apps/judicial-system/backend/src/app/modules/file/test/fileController/createCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/fileController/createCaseFile.spec.ts index 6a53c85efd3e..88525e99b8c6 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/fileController/createCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/fileController/createCaseFile.spec.ts @@ -68,7 +68,7 @@ describe('FileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.PROSECUTOR_APPEAL_STATEMENT_CASE_FILE, } @@ -76,7 +76,7 @@ describe('FileController - Create case file', () => { const timeStamp = randomDate() const caseFile = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.PROSECUTOR_APPEAL_STATEMENT_CASE_FILE, id: fileId, @@ -96,7 +96,7 @@ describe('FileController - Create case file', () => { expect(mockFileModel.create).toHaveBeenCalledWith({ type: 'text/plain', state: CaseFileState.STORED_IN_RVG, - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.PROSECUTOR_APPEAL_STATEMENT_CASE_FILE, caseId, @@ -122,14 +122,14 @@ describe('FileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } const fileId = uuid() const timeStamp = randomDate() const caseFile = { type: 'text/plain', - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, id: fileId, created: timeStamp, @@ -148,7 +148,7 @@ describe('FileController - Create case file', () => { expect(mockFileModel.create).toHaveBeenCalledWith({ type: 'text/plain', state: CaseFileState.STORED_IN_RVG, - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, caseId, name: 'test.txt', @@ -164,7 +164,7 @@ describe('FileController - Create case file', () => { const uuId = `-${uuid()}` const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } let then: Then @@ -176,7 +176,7 @@ describe('FileController - Create case file', () => { it('should throw bad gateway exception', () => { expect(then.error).toBeInstanceOf(BadRequestException) expect(then.error.message).toBe( - `uploads/${caseId}/${uuId}/test.txt is not a valid key for case ${caseId}`, + `${caseId}/${uuId}/test.txt is not a valid key for case ${caseId}`, ) }) }) @@ -187,7 +187,7 @@ describe('FileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } let then: Then diff --git a/apps/judicial-system/backend/src/app/modules/file/test/fileController/createPresignedPost.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/fileController/createPresignedPost.spec.ts index 18af35b86c17..1d265178b5da 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/fileController/createPresignedPost.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/fileController/createPresignedPost.spec.ts @@ -1,6 +1,7 @@ import { uuid } from 'uuidv4' import { + CaseState, indictmentCases, investigationCases, restrictionCases, @@ -53,7 +54,7 @@ describe('FileController - Create presigned post', () => { 'presigned post created for %s case', (type) => { const caseId = uuid() - const theCase = { id: caseId, type } as Case + const theCase = { id: caseId, type, state: CaseState.SUBMITTED } as Case const createPresignedPost: CreatePresignedPostDto = { fileName: 'test.txt', type: 'text/plain', @@ -63,11 +64,11 @@ describe('FileController - Create presigned post', () => { beforeEach(async () => { const mockCreatePresignedPost = mockAwsS3Service.createPresignedPost as jest.Mock - mockCreatePresignedPost.mockImplementationOnce((key: string) => + mockCreatePresignedPost.mockImplementationOnce((_1, _2, key: string) => Promise.resolve({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { - key, + key: `uploads/${key}`, bucket: 'island-is-dev-upload-judicial-system', 'X-Amz-Algorithm': 'Some Algorithm', 'X-Amz-Credential': 'Some Credentials', @@ -82,16 +83,14 @@ describe('FileController - Create presigned post', () => { then = await givenWhenThen(caseId, createPresignedPost, theCase) }) - it('should request a presigned post from AWS S3', () => { + it('should return a presigned post', () => { expect(mockAwsS3Service.createPresignedPost).toHaveBeenCalledWith( - expect.stringMatching( - new RegExp(`^uploads/${caseId}/.{36}/test.txt$`), - ), + type, + CaseState.SUBMITTED, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), 'text/plain', ) - }) - it('should return a presigned post', () => { expect(then.result).toEqual({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { @@ -104,6 +103,7 @@ describe('FileController - Create presigned post', () => { Policy: 'Some Policy', 'X-Amz-Signature': 'Some Signature', }, + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), }) expect(then.result.fields.key).toMatch( @@ -117,7 +117,11 @@ describe('FileController - Create presigned post', () => { 'presigned post created for %s case', (type) => { const caseId = uuid() - const theCase = { id: caseId, type } as Case + const theCase = { + id: caseId, + type, + state: CaseState.MAIN_HEARING, + } as Case const createPresignedPost: CreatePresignedPostDto = { fileName: 'test.txt', type: 'text/plain', @@ -127,11 +131,11 @@ describe('FileController - Create presigned post', () => { beforeEach(async () => { const mockCreatePresignedPost = mockAwsS3Service.createPresignedPost as jest.Mock - mockCreatePresignedPost.mockImplementationOnce((key: string) => + mockCreatePresignedPost.mockImplementationOnce((_1, _2, key: string) => Promise.resolve({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { - key, + key: `indictments/${key}`, bucket: 'island-is-dev-upload-judicial-system', 'X-Amz-Algorithm': 'Some Algorithm', 'X-Amz-Credential': 'Some Credentials', @@ -146,16 +150,14 @@ describe('FileController - Create presigned post', () => { then = await givenWhenThen(caseId, createPresignedPost, theCase) }) - it('should request a presigned post from AWS S3', () => { + it('should return a presigned post', () => { expect(mockAwsS3Service.createPresignedPost).toHaveBeenCalledWith( - expect.stringMatching( - new RegExp(`^indictments/${caseId}/.{36}/test.txt$`), - ), + type, + CaseState.MAIN_HEARING, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), 'text/plain', ) - }) - it('should return a presigned post', () => { expect(then.result).toEqual({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { @@ -168,6 +170,7 @@ describe('FileController - Create presigned post', () => { Policy: 'Some Policy', 'X-Amz-Signature': 'Some Signature', }, + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), }) expect(then.result.fields.key).toMatch( diff --git a/apps/judicial-system/backend/src/app/modules/file/test/fileController/deleteCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/fileController/deleteCaseFile.spec.ts index 892de744b60f..9252884e2ea5 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/fileController/deleteCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/fileController/deleteCaseFile.spec.ts @@ -1,10 +1,15 @@ import { uuid } from 'uuidv4' -import { CaseFileState } from '@island.is/judicial-system/types' +import { + CaseFileState, + CaseState, + CaseType, +} from '@island.is/judicial-system/types' import { createTestingFileModule } from '../createTestingFileModule' import { AwsS3Service } from '../../../aws-s3' +import { Case } from '../../../case' import { DeleteFileResponse } from '../../models/deleteFile.response' import { CaseFile } from '../../models/file.model' @@ -15,6 +20,7 @@ interface Then { type GivenWhenThen = ( caseId: string, + theCase: Case, fileId: string, casefile: CaseFile, ) => Promise @@ -36,13 +42,14 @@ describe('FileController - Delete case file', () => { givenWhenThen = async ( caseId: string, + theCase: Case, fileId: string, caseFile: CaseFile, ): Promise => { const then = {} as Then await fileController - .deleteCaseFile(caseId, fileId, caseFile) + .deleteCaseFile(caseId, theCase, fileId, caseFile) .then((result) => (then.result = result)) .catch((error) => (then.error = error)) @@ -52,41 +59,38 @@ describe('FileController - Delete case file', () => { describe('database update', () => { const caseId = uuid() + const caseType = CaseType.INDICTMENT + const caseState = CaseState.DRAFT + const theCase = { id: caseId, type: caseType, state: caseState } as Case const fileId = uuid() - const caseFile = { id: fileId } as CaseFile - - beforeEach(async () => { - await givenWhenThen(caseId, fileId, caseFile) - }) - - it('should update the case file status in the database', () => { - expect(mockFileModel.update).toHaveBeenCalledWith( - { state: CaseFileState.DELETED, key: null }, - { where: { id: fileId } }, - ) - }) - }) - - describe('AWS S3 removal', () => { - const caseId = uuid() - const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile + let then: Then beforeEach(async () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([1]) - await givenWhenThen(caseId, fileId, caseFile) + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) - it('should attempt to remove from AWS S3', () => { - expect(mockAwsS3Service.deleteObject).toHaveBeenCalledWith(key) + it('should delete the case file', () => { + expect(mockFileModel.update).toHaveBeenCalledWith( + { state: CaseFileState.DELETED, key: null }, + { where: { id: fileId } }, + ) + expect(mockAwsS3Service.deleteObject).toHaveBeenCalledWith( + caseType, + caseState, + key, + ) + expect(then.result).toEqual({ success: true }) }) }) describe('AWS S3 removal skipped', () => { const caseId = uuid() + const theCase = { id: caseId } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile @@ -94,7 +98,7 @@ describe('FileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([1]) - await givenWhenThen(caseId, fileId, caseFile) + await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should not attempt to remove from AWS S3', () => { @@ -102,26 +106,9 @@ describe('FileController - Delete case file', () => { }) }) - describe('case file deleted', () => { - const caseId = uuid() - const fileId = uuid() - const caseFile = { id: fileId } as CaseFile - let then: Then - - beforeEach(async () => { - const mockUpdate = mockFileModel.update as jest.Mock - mockUpdate.mockResolvedValueOnce([1]) - - then = await givenWhenThen(caseId, fileId, caseFile) - }) - - it('should return success', () => { - expect(then.result).toEqual({ success: true }) - }) - }) - describe('case file not deleted', () => { const caseId = uuid() + const theCase = { id: caseId } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile let then: Then @@ -130,7 +117,7 @@ describe('FileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([0]) - then = await givenWhenThen(caseId, fileId, caseFile) + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should return failure', () => { @@ -140,6 +127,7 @@ describe('FileController - Delete case file', () => { describe('database update fails', () => { const caseId = uuid() + const theCase = { id: caseId } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile let then: Then @@ -148,7 +136,7 @@ describe('FileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, fileId, caseFile) + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should throw error', () => { diff --git a/apps/judicial-system/backend/src/app/modules/file/test/fileController/getCaseFileSignedUrl.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/fileController/getCaseFileSignedUrl.spec.ts index 5e158ac58ba2..6423672112cf 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/fileController/getCaseFileSignedUrl.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/fileController/getCaseFileSignedUrl.spec.ts @@ -2,6 +2,8 @@ import { uuid } from 'uuidv4' import { NotFoundException } from '@nestjs/common' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingFileModule } from '../createTestingFileModule' import { AwsS3Service } from '../../../aws-s3' @@ -50,53 +52,17 @@ describe('FileController - Get case file signed url', () => { } }) - describe('AWS S3 existance check', () => { - const caseId = uuid() - const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` - const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case - let mockObjectExists: jest.Mock - - beforeEach(async () => { - mockObjectExists = mockAwsS3Service.objectExists as jest.Mock - - await givenWhenThen(caseId, theCase, fileId, caseFile) - }) - - it('should check if the file exists in AWS S3', () => { - expect(mockObjectExists).toHaveBeenCalledWith(key) - }) - }) - - describe('AWS S3 get signed url', () => { - const caseId = uuid() - const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` - const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case - let mockGetSignedUrl: jest.Mock - - beforeEach(async () => { - mockGetSignedUrl = mockAwsS3Service.getSignedUrl as jest.Mock - const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock - mockObjectExists.mockResolvedValueOnce(true) - - await givenWhenThen(caseId, theCase, fileId, caseFile) - }) - - it('should get signed url from AWS S3', () => { - expect(mockGetSignedUrl).toHaveBeenCalledWith(key) - }) - }) - describe('signed url created', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - const theCase = { id: uuid() } as Case - const url = uuid() + const theCase = { + id: uuid(), + type: CaseType.ADMISSION_TO_FACILITY, + state: CaseState.RECEIVED, + } as Case + const url = `uploads/${key}` let then: Then beforeEach(async () => { @@ -108,34 +74,32 @@ describe('FileController - Get case file signed url', () => { then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) - it('should return the signed url', () => { + it('should create a signed url', () => { + expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + ) + expect(mockAwsS3Service.getSignedUrl).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + undefined, + ) expect(then.result).toEqual({ url }) }) }) - describe('file not stored in AWS S3', () => { - const caseId = uuid() - const fileId = uuid() - const caseFile = { id: fileId } as CaseFile - const theCase = {} as Case - let then: Then - - beforeEach(async () => { - then = await givenWhenThen(caseId, theCase, fileId, caseFile) - }) - - it('should throw not found exceptoin', () => { - expect(then.error).toBeInstanceOf(NotFoundException) - expect(then.error.message).toBe(`File ${fileId} does not exist in AWS S3`) - }) - }) - describe('file not found in AWS S3', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case + const theCase = { + id: caseId, + type: CaseType.INDICTMENT, + state: CaseState.DRAFT, + } as Case let mockUpdate: jest.Mock let then: Then @@ -147,44 +111,20 @@ describe('FileController - Get case file signed url', () => { then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) - it('should remove the key', () => { + it('should remove the key and throw', () => { expect(mockUpdate).toHaveBeenCalledWith( { key: null }, { where: { id: fileId } }, ) - }) - - it('should throw not found exceptoin', () => { expect(then.error).toBeInstanceOf(NotFoundException) expect(then.error.message).toBe(`File ${fileId} does not exist in AWS S3`) }) }) - describe('remote existance check fails', () => { - const caseId = uuid() - const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` - const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case - let then: Then - - beforeEach(async () => { - const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock - mockObjectExists.mockRejectedValueOnce(new Error('Some error')) - - then = await givenWhenThen(caseId, theCase, fileId, caseFile) - }) - - it('should throw error', () => { - expect(then.error).toBeInstanceOf(Error) - expect(then.error.message).toBe('Some error') - }) - }) - describe('signed url creation fails', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const theCase = {} as Case let then: Then diff --git a/apps/judicial-system/backend/src/app/modules/file/test/fileController/uploadCaseFileToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/fileController/uploadCaseFileToCourt.spec.ts index 9bcfe1fc294f..b249a9b8e41c 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/fileController/uploadCaseFileToCourt.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/fileController/uploadCaseFileToCourt.spec.ts @@ -6,6 +6,8 @@ import { NotFoundException } from '@nestjs/common' import { CaseFileCategory, CaseFileState, + CaseState, + CaseType, User, } from '@island.is/judicial-system/types' @@ -65,34 +67,39 @@ describe('FileController - Upload case file to court', () => { describe('AWS S3 existance check', () => { const user = {} as User const caseId = uuid() - const theCase = { id: caseId } as Case + const theCase = { + id: caseId, + type: CaseType.ELECTRONIC_DATA_DISCOVERY_INVESTIGATION, + state: CaseState.DISMISSED, + } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - let mockObjectExists: jest.Mock beforeEach(async () => { - mockObjectExists = mockAwsS3Service.objectExists as jest.Mock - await givenWhenThen(caseId, fileId, user, theCase, caseFile) }) it('should check if the file exists in AWS S3', () => { - expect(mockObjectExists).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + ) }) }) describe('AWS S3 get file', () => { const user = {} as User const caseId = uuid() - const theCase = { id: caseId } as Case + const type = CaseType.INDICTMENT + const state = CaseState.REJECTED + const theCase = { id: caseId, type, state } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - let mockGetObject: jest.Mock beforeEach(async () => { - mockGetObject = mockAwsS3Service.getObject as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(true) @@ -100,7 +107,7 @@ describe('FileController - Upload case file to court', () => { }) it('should get the file from AWS S3', () => { - expect(mockGetObject).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(type, state, key) }) }) @@ -115,7 +122,7 @@ describe('FileController - Upload case file to court', () => { courtCaseNumber, } as Case const fileId = uuid() - const key = `indictments/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const fileName = 'test.txt' const fileType = 'text/plain' const caseFile = { @@ -174,7 +181,7 @@ describe('FileController - Upload case file to court', () => { courtCaseNumber, } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const fileName = 'test.txt' const fileType = 'text/plain' const caseFile = { @@ -218,14 +225,12 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') const documentId = uuid() - let mockUpdate: jest.Mock beforeEach(async () => { - mockUpdate = mockFileModel.update as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(true) const mockGetObject = mockAwsS3Service.getObject as jest.Mock @@ -237,7 +242,7 @@ describe('FileController - Upload case file to court', () => { }) it('should update case file state', () => { - expect(mockUpdate).toHaveBeenCalledWith( + expect(mockFileModel.update).toHaveBeenCalledWith( { state: CaseFileState.STORED_IN_COURT }, { where: { id: fileId } }, ) @@ -249,7 +254,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then @@ -261,8 +266,6 @@ describe('FileController - Upload case file to court', () => { mockGetObject.mockResolvedValueOnce(content) const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([1]) - const mockDeleteObject = mockAwsS3Service.deleteObject as jest.Mock - mockDeleteObject.mockResolvedValueOnce(true) then = await givenWhenThen(caseId, fileId, user, theCase, caseFile) }) @@ -277,7 +280,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then @@ -341,13 +344,11 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - let mockUpdate: jest.Mock let then: Then beforeEach(async () => { - mockUpdate = mockFileModel.update as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(false) @@ -355,7 +356,7 @@ describe('FileController - Upload case file to court', () => { }) it('should remove the key', () => { - expect(mockUpdate).toHaveBeenCalledWith( + expect(mockFileModel.update).toHaveBeenCalledWith( { key: null }, { where: { id: fileId } }, ) @@ -372,7 +373,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile let then: Then @@ -394,7 +395,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile let then: Then @@ -418,7 +419,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then @@ -445,7 +446,7 @@ describe('FileController - Upload case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then diff --git a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/archiveCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/archiveCaseFile.spec.ts index 6bef94ad98b2..a5b812d91173 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/archiveCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/archiveCaseFile.spec.ts @@ -1,5 +1,7 @@ import { uuid } from 'uuidv4' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingFileModule } from '../createTestingFileModule' import { AwsS3Service } from '../../../aws-s3' @@ -21,15 +23,13 @@ type GivenWhenThen = ( describe('InternalFileController - Archive case files', () => { let mockAwsS3Service: AwsS3Service - let mockFileModel: typeof CaseFile let givenWhenThen: GivenWhenThen beforeEach(async () => { - const { awsS3Service, fileModel, internalFileController } = + const { awsS3Service, internalFileController } = await createTestingFileModule() mockAwsS3Service = awsS3Service - mockFileModel = fileModel givenWhenThen = async ( caseId: string, @@ -50,13 +50,15 @@ describe('InternalFileController - Archive case files', () => { describe('case file delivered', () => { const caseId = uuid() + const caseType = CaseType.INDICTMENT + const caseState = CaseState.COMPLETED const fileId = uuid() const surrogateKey = uuid() - const key = `indictments/${caseId}/${surrogateKey}/test.txt` + const key = `${caseId}/${surrogateKey}/test.txt` const newKey = `indictments/completed/${caseId}/${surrogateKey}/test.txt` const fileName = 'test.txt' const fileType = 'text/plain' - const theCase = {} as Case + const theCase = { id: caseId, type: caseType, state: caseState } as Case const caseFile = { id: fileId, caseId, @@ -67,32 +69,18 @@ describe('InternalFileController - Archive case files', () => { let then: Then beforeEach(async () => { - const mockCopyObject = mockAwsS3Service.copyObject as jest.Mock - mockCopyObject.mockResolvedValueOnce(newKey) - const mockUpdate = mockFileModel.update as jest.Mock - mockUpdate.mockResolvedValueOnce([1]) - const mockDeleteObject = mockAwsS3Service.deleteObject as jest.Mock - mockDeleteObject.mockResolvedValueOnce(true) + const mockArchiveObject = mockAwsS3Service.archiveObject as jest.Mock + mockArchiveObject.mockResolvedValueOnce(newKey) then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) - it('should copy the file to archive bucket in AWS S3', () => { - expect(mockAwsS3Service.copyObject).toHaveBeenCalledWith(key, newKey) - }) - - it('should update case file state', () => { - expect(mockFileModel.update).toHaveBeenCalledWith( - { key: newKey }, - { where: { id: fileId } }, + it('should archive the case file', () => { + expect(mockAwsS3Service.archiveObject).toHaveBeenCalledWith( + caseType, + caseState, + key, ) - }) - - it('should try to delete the file from AWS S3', () => { - expect(mockAwsS3Service.deleteObject).toHaveBeenCalledWith(key) - }) - - it('should return success', () => { expect(then.result).toEqual({ delivered: true }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourt.spec.ts index 67adfa0eec0b..6931ead61cb2 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourt.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourt.spec.ts @@ -6,6 +6,8 @@ import { NotFoundException } from '@nestjs/common' import { CaseFileCategory, CaseFileState, + CaseState, + CaseType, User, } from '@island.is/judicial-system/types' @@ -65,15 +67,19 @@ describe('InternalFileController - Deliver case file to court', () => { describe('case file delivered', () => { const caseId = uuid() + const caseType = CaseType.CUSTODY + const caseState = CaseState.RECEIVED const courtId = uuid() const courtCaseNumber = 'R-999/2021' const theCase = { id: caseId, + type: caseType, + state: caseState, courtId, courtCaseNumber, } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const fileName = 'test.txt' const fileType = 'text/plain' const caseFile = { @@ -100,11 +106,19 @@ describe('InternalFileController - Deliver case file to court', () => { }) it('should check if the file exists in AWS S3', () => { - expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith( + caseType, + caseState, + key, + ) }) it('should get the file from AWS S3', () => { - expect(mockAwsS3Service.getObject).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.getObject).toHaveBeenCalledWith( + caseType, + caseState, + key, + ) }) it('should upload the file to court', () => { @@ -159,7 +173,7 @@ describe('InternalFileController - Deliver case file to court', () => { courtCaseNumber, } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const fileName = 'test.txt' const fileType = 'text/plain' const caseFile = { @@ -170,10 +184,8 @@ describe('InternalFileController - Deliver case file to court', () => { category: caseFileCategory, } as CaseFile const content = Buffer.from('Test content') - let mockCreateDocument: jest.Mock beforeEach(async () => { - mockCreateDocument = mockCourtService.createDocument as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(true) const mockGetObject = mockAwsS3Service.getObject as jest.Mock @@ -183,7 +195,7 @@ describe('InternalFileController - Deliver case file to court', () => { }) it('should upload the file to court', () => { - expect(mockCreateDocument).toHaveBeenCalledWith( + expect(mockCourtService.createDocument).toHaveBeenCalledWith( user, caseId, courtId, @@ -202,7 +214,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then @@ -263,7 +275,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile let then: Then @@ -291,7 +303,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile let then: Then @@ -312,7 +324,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile let then: Then @@ -335,7 +347,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then @@ -361,7 +373,7 @@ describe('InternalFileController - Deliver case file to court', () => { const caseId = uuid() const theCase = { id: caseId } as Case const fileId = uuid() - const key = `uploads/${caseId}/${uuid()}/test.txt` + const key = `${caseId}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const content = Buffer.from('Test content') let then: Then diff --git a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourtOfAppeals.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourtOfAppeals.spec.ts index 61a1a636af76..c20557346a9e 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourtOfAppeals.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/internalFileController/deliverCaseFileToCourtOfAppeals.spec.ts @@ -4,6 +4,7 @@ import { type ConfigType } from '@island.is/nest/config' import { CaseFileCategory, + CaseState, CaseType, User, } from '@island.is/judicial-system/types' @@ -47,6 +48,7 @@ describe('InternalFileController - Deliver case file to court of appeals', () => const theCase = { id: caseId, type: CaseType.CUSTODY, + state: CaseState.ACCEPTED, appealCaseNumber, caseFiles: [caseFile], } as Case @@ -98,8 +100,14 @@ describe('InternalFileController - Deliver case file to court of appeals', () => }) it('should return success', () => { - expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + ) expect(mockAwsS3Service.getSignedUrl).toHaveBeenCalledWith( + theCase.type, + theCase.state, key, mockFileConfig.robotS3TimeToLiveGet, ) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFile.spec.ts index 2866c817baee..448b6983a033 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFile.spec.ts @@ -68,7 +68,7 @@ describe('limitedAccessFileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.DEFENDANT_APPEAL_CASE_FILE, } @@ -76,7 +76,7 @@ describe('limitedAccessFileController - Create case file', () => { const timeStamp = randomDate() const caseFile = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.DEFENDANT_APPEAL_CASE_FILE, id: fileId, @@ -96,7 +96,7 @@ describe('limitedAccessFileController - Create case file', () => { expect(mockFileModel.create).toHaveBeenCalledWith({ type: 'text/plain', state: CaseFileState.STORED_IN_RVG, - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, category: CaseFileCategory.DEFENDANT_APPEAL_CASE_FILE, caseId, @@ -122,14 +122,14 @@ describe('limitedAccessFileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } const fileId = uuid() const timeStamp = randomDate() const caseFile = { type: 'text/plain', - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, id: fileId, created: timeStamp, @@ -148,7 +148,7 @@ describe('limitedAccessFileController - Create case file', () => { expect(mockFileModel.create).toHaveBeenCalledWith({ type: 'text/plain', state: CaseFileState.STORED_IN_RVG, - key: `indictments/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, caseId, name: 'test.txt', @@ -164,7 +164,7 @@ describe('limitedAccessFileController - Create case file', () => { const uuId = `-${uuid()}` const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } let then: Then @@ -176,7 +176,7 @@ describe('limitedAccessFileController - Create case file', () => { it('should throw bad gateway exception', () => { expect(then.error).toBeInstanceOf(BadRequestException) expect(then.error.message).toBe( - `uploads/${caseId}/${uuId}/test.txt is not a valid key for case ${caseId}`, + `${caseId}/${uuId}/test.txt is not a valid key for case ${caseId}`, ) }) }) @@ -187,7 +187,7 @@ describe('limitedAccessFileController - Create case file', () => { const uuId = uuid() const createCaseFile: CreateFileDto = { type: 'text/plain', - key: `uploads/${caseId}/${uuId}/test.txt`, + key: `${caseId}/${uuId}/test.txt`, size: 99, } let then: Then diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPost.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPost.spec.ts index c01704b5b465..ef3d724685b4 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPost.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPost.spec.ts @@ -1,6 +1,7 @@ import { uuid } from 'uuidv4' import { + CaseState, indictmentCases, investigationCases, restrictionCases, @@ -54,7 +55,7 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () 'presigned post created for %s case', (type) => { const caseId = uuid() - const theCase = { id: caseId, type } as Case + const theCase = { id: caseId, type, state: CaseState.DRAFT } as Case const createPresignedPost: CreatePresignedPostDto = { fileName: 'test.txt', type: 'text/plain', @@ -64,11 +65,11 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () beforeEach(async () => { const mockCreatePresignedPost = mockAwsS3Service.createPresignedPost as jest.Mock - mockCreatePresignedPost.mockImplementationOnce((key: string) => + mockCreatePresignedPost.mockImplementationOnce((_1, _2, key: string) => Promise.resolve({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { - key, + key: `uploads/${key}`, bucket: 'island-is-dev-upload-judicial-system', 'X-Amz-Algorithm': 'Some Algorithm', 'X-Amz-Credential': 'Some Credentials', @@ -83,16 +84,14 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () then = await givenWhenThen(caseId, createPresignedPost, theCase) }) - it('should request a presigned post from AWS S3', () => { + it('should return a presigned post', () => { expect(mockAwsS3Service.createPresignedPost).toHaveBeenCalledWith( - expect.stringMatching( - new RegExp(`^uploads/${caseId}/.{36}/test.txt$`), - ), + type, + CaseState.DRAFT, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), 'text/plain', ) - }) - it('should return a presigned post', () => { expect(then.result).toEqual({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { @@ -105,6 +104,7 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () Policy: 'Some Policy', 'X-Amz-Signature': 'Some Signature', }, + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), }) expect(then.result.fields.key).toMatch( @@ -118,7 +118,7 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () 'presigned post created for %s case', (type) => { const caseId = uuid() - const theCase = { id: caseId, type } as Case + const theCase = { id: caseId, type, state: CaseState.DRAFT } as Case const createPresignedPost: CreatePresignedPostDto = { fileName: 'test.txt', type: 'text/plain', @@ -128,11 +128,11 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () beforeEach(async () => { const mockCreatePresignedPost = mockAwsS3Service.createPresignedPost as jest.Mock - mockCreatePresignedPost.mockImplementationOnce((key: string) => + mockCreatePresignedPost.mockImplementationOnce((_1, _2, key: string) => Promise.resolve({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { - key, + key: `indictments/${key}`, bucket: 'island-is-dev-upload-judicial-system', 'X-Amz-Algorithm': 'Some Algorithm', 'X-Amz-Credential': 'Some Credentials', @@ -147,16 +147,14 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () then = await givenWhenThen(caseId, createPresignedPost, theCase) }) - it('should request a presigned post from AWS S3', () => { + it('should return a presigned post', () => { expect(mockAwsS3Service.createPresignedPost).toHaveBeenCalledWith( - expect.stringMatching( - new RegExp(`^indictments/${caseId}/.{36}/test.txt$`), - ), + type, + CaseState.DRAFT, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), 'text/plain', ) - }) - it('should return a presigned post', () => { expect(then.result).toEqual({ url: 'https://s3.eu-west-1.amazonaws.com/island-is-dev-upload-judicial-system', fields: { @@ -169,6 +167,7 @@ describe('LimitedAccesslimitedAccessFileController - Create presigned post', () Policy: 'Some Policy', 'X-Amz-Signature': 'Some Signature', }, + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), }) expect(then.result.fields.key).toMatch( diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFile.spec.ts index 8bc6e5f64d3d..bcfd348c53a3 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFile.spec.ts @@ -1,10 +1,15 @@ import { uuid } from 'uuidv4' -import { CaseFileState } from '@island.is/judicial-system/types' +import { + CaseFileState, + CaseState, + CaseType, +} from '@island.is/judicial-system/types' import { createTestingFileModule } from '../createTestingFileModule' import { AwsS3Service } from '../../../aws-s3' +import { Case } from '../../../case' import { DeleteFileResponse } from '../../models/deleteFile.response' import { CaseFile } from '../../models/file.model' @@ -15,6 +20,7 @@ interface Then { type GivenWhenThen = ( caseId: string, + theCase: Case, fileId: string, casefile: CaseFile, ) => Promise @@ -36,13 +42,14 @@ describe('LimitedAccessFileController - Delete case file', () => { givenWhenThen = async ( caseId: string, + theCase: Case, fileId: string, caseFile: CaseFile, ): Promise => { const then = {} as Then await limitedAccessFileController - .deleteCaseFile(caseId, fileId, caseFile) + .deleteCaseFile(caseId, theCase, fileId, caseFile) .then((result) => (then.result = result)) .catch((error) => (then.error = error)) @@ -50,13 +57,21 @@ describe('LimitedAccessFileController - Delete case file', () => { } }) - describe('database update', () => { + describe('case file deleted', () => { const caseId = uuid() + const caseType = CaseType.RESTRAINING_ORDER + const caseState = CaseState.DRAFT + const theCase = { id: caseId, type: caseType, state: caseState } as Case const fileId = uuid() - const caseFile = { id: fileId } as CaseFile + const key = `${uuid()}/${uuid()}/test.txt` + const caseFile = { id: fileId, key } as CaseFile + let then: Then beforeEach(async () => { - await givenWhenThen(caseId, fileId, caseFile) + const mockUpdate = mockFileModel.update as jest.Mock + mockUpdate.mockResolvedValueOnce([1]) + + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should update the case file status in the database', () => { @@ -64,29 +79,20 @@ describe('LimitedAccessFileController - Delete case file', () => { { state: CaseFileState.DELETED, key: null }, { where: { id: fileId } }, ) - }) - }) - - describe('AWS S3 removal', () => { - const caseId = uuid() - const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` - const caseFile = { id: fileId, key } as CaseFile - - beforeEach(async () => { - const mockUpdate = mockFileModel.update as jest.Mock - mockUpdate.mockResolvedValueOnce([1]) - - await givenWhenThen(caseId, fileId, caseFile) - }) - - it('should attempt to remove from AWS S3', () => { - expect(mockAwsS3Service.deleteObject).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.deleteObject).toHaveBeenCalledWith( + caseType, + caseState, + key, + ) + expect(then.result).toEqual({ success: true }) }) }) describe('AWS S3 removal skipped', () => { const caseId = uuid() + const caseType = CaseType.CUSTODY + const caseSate = CaseState.SUBMITTED + const theCase = { id: caseId, type: caseType, state: caseSate } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile @@ -94,7 +100,7 @@ describe('LimitedAccessFileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([1]) - await givenWhenThen(caseId, fileId, caseFile) + await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should not attempt to remove from AWS S3', () => { @@ -102,26 +108,9 @@ describe('LimitedAccessFileController - Delete case file', () => { }) }) - describe('case file deleted', () => { - const caseId = uuid() - const fileId = uuid() - const caseFile = { id: fileId } as CaseFile - let then: Then - - beforeEach(async () => { - const mockUpdate = mockFileModel.update as jest.Mock - mockUpdate.mockResolvedValueOnce([1]) - - then = await givenWhenThen(caseId, fileId, caseFile) - }) - - it('should return success', () => { - expect(then.result).toEqual({ success: true }) - }) - }) - describe('case file not deleted', () => { const caseId = uuid() + const theCase = { id: caseId } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile let then: Then @@ -130,7 +119,7 @@ describe('LimitedAccessFileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockResolvedValueOnce([0]) - then = await givenWhenThen(caseId, fileId, caseFile) + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should return failure', () => { @@ -140,6 +129,7 @@ describe('LimitedAccessFileController - Delete case file', () => { describe('database update fails', () => { const caseId = uuid() + const theCase = { id: caseId } as Case const fileId = uuid() const caseFile = { id: fileId } as CaseFile let then: Then @@ -148,7 +138,7 @@ describe('LimitedAccessFileController - Delete case file', () => { const mockUpdate = mockFileModel.update as jest.Mock mockUpdate.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, fileId, caseFile) + then = await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should throw error', () => { diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/getCaseFileSignedUrl.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/getCaseFileSignedUrl.spec.ts index 90d0ae806cb9..6f6dbc7675c8 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/getCaseFileSignedUrl.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/getCaseFileSignedUrl.spec.ts @@ -2,6 +2,8 @@ import { uuid } from 'uuidv4' import { NotFoundException } from '@nestjs/common' +import { CaseState, CaseType } from '@island.is/judicial-system/types' + import { createTestingFileModule } from '../createTestingFileModule' import { AwsS3Service } from '../../../aws-s3' @@ -53,33 +55,39 @@ describe('LimitedAccessFileController - Get case file signed url', () => { describe('AWS S3 existance check', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case - let mockObjectExists: jest.Mock + const theCase = { + id: caseId, + type: CaseType.INTERNET_USAGE, + state: CaseState.ACCEPTED, + } as Case beforeEach(async () => { - mockObjectExists = mockAwsS3Service.objectExists as jest.Mock - await givenWhenThen(caseId, theCase, fileId, caseFile) }) it('should check if the file exists in AWS S3', () => { - expect(mockObjectExists).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.objectExists).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + ) }) }) describe('AWS S3 get signed url', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile - const theCase = {} as Case - - let mockGetSignedUrl: jest.Mock + const theCase = { + id: uuid(), + type: CaseType.PHONE_TAPPING, + state: CaseState.SUBMITTED, + } as Case beforeEach(async () => { - mockGetSignedUrl = mockAwsS3Service.getSignedUrl as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(true) @@ -87,14 +95,19 @@ describe('LimitedAccessFileController - Get case file signed url', () => { }) it('should get signed url from AWS S3', () => { - expect(mockGetSignedUrl).toHaveBeenCalledWith(key) + expect(mockAwsS3Service.getSignedUrl).toHaveBeenCalledWith( + theCase.type, + theCase.state, + key, + undefined, + ) }) }) describe('signed url created', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const theCase = {} as Case @@ -136,15 +149,12 @@ describe('LimitedAccessFileController - Get case file signed url', () => { describe('file not found in AWS S3', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const theCase = {} as Case - - let mockUpdate: jest.Mock let then: Then beforeEach(async () => { - mockUpdate = mockFileModel.update as jest.Mock const mockObjectExists = mockAwsS3Service.objectExists as jest.Mock mockObjectExists.mockResolvedValueOnce(false) @@ -152,7 +162,7 @@ describe('LimitedAccessFileController - Get case file signed url', () => { }) it('should remove the key', () => { - expect(mockUpdate).toHaveBeenCalledWith( + expect(mockFileModel.update).toHaveBeenCalledWith( { key: null }, { where: { id: fileId } }, ) @@ -167,7 +177,7 @@ describe('LimitedAccessFileController - Get case file signed url', () => { describe('remote existance check fails', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const theCase = {} as Case @@ -189,7 +199,7 @@ describe('LimitedAccessFileController - Get case file signed url', () => { describe('signed url creation fails', () => { const caseId = uuid() const fileId = uuid() - const key = `uploads/${uuid()}/${uuid()}/test.txt` + const key = `${uuid()}/${uuid()}/test.txt` const caseFile = { id: fileId, key } as CaseFile const theCase = {} as Case diff --git a/apps/judicial-system/backend/src/app/modules/institution/test/getAll.spec.ts b/apps/judicial-system/backend/src/app/modules/institution/test/getAll.spec.ts index 7b06f2966219..9cdcd62bfd50 100644 --- a/apps/judicial-system/backend/src/app/modules/institution/test/getAll.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/institution/test/getAll.spec.ts @@ -39,7 +39,7 @@ describe('InstitutionController - Get all', () => { beforeEach(async () => { const mockFindAll = mockInstitutionModel.findAll as jest.Mock - mockFindAll.mockReturnValueOnce(institutions) + mockFindAll.mockResolvedValueOnce(institutions) then = await givenWhenThen() }) diff --git a/apps/judicial-system/backend/src/app/modules/police/index.ts b/apps/judicial-system/backend/src/app/modules/police/index.ts index 4540547920fd..6f0613c334bc 100644 --- a/apps/judicial-system/backend/src/app/modules/police/index.ts +++ b/apps/judicial-system/backend/src/app/modules/police/index.ts @@ -1 +1,5 @@ -export { CourtDocumentType, PoliceService } from './police.service' +export { + PoliceDocumentType, + PoliceDocument, + PoliceService, +} from './police.service' diff --git a/apps/judicial-system/backend/src/app/modules/police/police.controller.ts b/apps/judicial-system/backend/src/app/modules/police/police.controller.ts index 2d6321e6bc14..ff672881afd0 100644 --- a/apps/judicial-system/backend/src/app/modules/police/police.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/police/police.controller.ts @@ -106,6 +106,7 @@ export class PoliceController { return this.policeService.uploadPoliceCaseFile( caseId, theCase.type, + theCase.state, uploadPoliceCaseFile, user, ) diff --git a/apps/judicial-system/backend/src/app/modules/police/police.service.ts b/apps/judicial-system/backend/src/app/modules/police/police.service.ts index cc828f7e13bb..5380379da208 100644 --- a/apps/judicial-system/backend/src/app/modules/police/police.service.ts +++ b/apps/judicial-system/backend/src/app/modules/police/police.service.ts @@ -22,11 +22,7 @@ import { } from '@island.is/shared/utils/server' import type { User } from '@island.is/judicial-system/types' -import { - CaseState, - CaseType, - isIndictmentCase, -} from '@island.is/judicial-system/types' +import { CaseState, CaseType } from '@island.is/judicial-system/types' import { nowFactory } from '../../factories' import { AwsS3Service } from '../aws-s3' @@ -37,7 +33,7 @@ import { PoliceCaseInfo } from './models/policeCaseInfo.model' import { UploadPoliceCaseFileResponse } from './models/uploadPoliceCaseFile.response' import { policeModuleConfig } from './police.config' -export enum CourtDocumentType { +export enum PoliceDocumentType { RVKR = 'RVKR', // Krafa RVTB = 'RVTB', // Þingbók RVUR = 'RVUR', // Úrskurður @@ -48,6 +44,11 @@ export enum CourtDocumentType { RVMG = 'RVMG', // Málsgögn } +export interface PoliceDocument { + type: PoliceDocumentType + courtDocument: string +} + const getChapter = (category?: string): number | undefined => { if (!category) { return undefined @@ -164,6 +165,7 @@ export class PoliceService { private async throttleUploadPoliceCaseFile( caseId: string, caseType: CaseType, + caseState: CaseState, uploadPoliceCaseFile: UploadPoliceCaseFileDto, user: User, ): Promise { @@ -221,11 +223,9 @@ export class PoliceService { }) }) - const key = `${ - isIndictmentCase(caseType) ? 'indictments' : 'uploads' - }/${caseId}/${uuid()}/${uploadPoliceCaseFile.name}` + const key = `${caseId}/${uuid()}/${uploadPoliceCaseFile.name}` - await this.awsS3Service.putObject(key, pdf) + await this.awsS3Service.putObject(caseType, caseState, key, pdf) return { key, size: pdf.length } } @@ -416,12 +416,14 @@ export class PoliceService { async uploadPoliceCaseFile( caseId: string, caseType: CaseType, + caseState: CaseState, uploadPoliceCaseFile: UploadPoliceCaseFileDto, user: User, ): Promise { this.throttle = this.throttleUploadPoliceCaseFile( caseId, caseType, + caseState, uploadPoliceCaseFile, user, ) @@ -439,7 +441,7 @@ export class PoliceService { defendantNationalId: string, validToDate: Date, caseConclusion: string, - courtDocuments: { type: CourtDocumentType; courtDocument: string }[], + courtDocuments: PoliceDocument[], ): Promise { return this.fetchPoliceCaseApi( `${this.xRoadPath}/V2/UpdateRVCase/${caseId}`, diff --git a/apps/judicial-system/backend/src/app/modules/police/test/updatePoliceCase.spec.ts b/apps/judicial-system/backend/src/app/modules/police/test/updatePoliceCase.spec.ts index 961783990ed6..c538ced0596e 100644 --- a/apps/judicial-system/backend/src/app/modules/police/test/updatePoliceCase.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/police/test/updatePoliceCase.spec.ts @@ -14,7 +14,7 @@ import { createTestingPoliceModule } from './createTestingPoliceModule' import { randomDate } from '../../../test' import { policeModuleConfig } from '../police.config' -import { CourtDocumentType } from '../police.service' +import { PoliceDocumentType } from '../police.service' jest.mock('node-fetch') @@ -36,8 +36,8 @@ describe('PoliceController - Update Police Case', () => { const validToDate = randomDate() const caseConclusion = 'test conclusion' const courtDocuments = [ - { type: CourtDocumentType.RVKR, courtDocument: 'test request pdf' }, - { type: CourtDocumentType.RVTB, courtDocument: 'test court record pdf' }, + { type: PoliceDocumentType.RVKR, courtDocument: 'test request pdf' }, + { type: PoliceDocumentType.RVTB, courtDocument: 'test court record pdf' }, ] let mockConfig: ConfigType diff --git a/apps/judicial-system/backend/src/app/modules/police/test/uploadPoliceCaseFile.spec.ts b/apps/judicial-system/backend/src/app/modules/police/test/uploadPoliceCaseFile.spec.ts index ba21a64a5b98..771661cc29bb 100644 --- a/apps/judicial-system/backend/src/app/modules/police/test/uploadPoliceCaseFile.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/police/test/uploadPoliceCaseFile.spec.ts @@ -4,7 +4,7 @@ import { uuid } from 'uuidv4' import { BadGatewayException, NotFoundException } from '@nestjs/common' -import { CaseType, User } from '@island.is/judicial-system/types' +import { CaseState, CaseType, User } from '@island.is/judicial-system/types' import { createTestingPoliceModule } from './createTestingPoliceModule' @@ -22,6 +22,8 @@ interface Then { type GivenWhenThen = ( caseId: string, + caseType: CaseType, + caseSate: CaseState, user: User, uploadPoliceCaseFile: UploadPoliceCaseFileDto, ) => Promise @@ -35,8 +37,13 @@ describe('PoliceController - Upload police case file', () => { mockAwsS3Service = awsS3Service + const mockPutObject = mockAwsS3Service.putObject as jest.Mock + mockPutObject.mockRejectedValue(new Error('Some error')) + givenWhenThen = async ( caseId: string, + caseType: CaseType, + caseSate: CaseState, user: User, uploadPoliceCaseFile: UploadPoliceCaseFileDto, ): Promise => { @@ -44,7 +51,9 @@ describe('PoliceController - Upload police case file', () => { await policeController .uploadPoliceCaseFile(caseId, user, uploadPoliceCaseFile, { - type: CaseType.CUSTODY, + id: caseId, + type: caseType, + state: caseSate, } as Case) .then((result) => (then.result = result)) .catch((error) => (then.error = error)) @@ -53,67 +62,66 @@ describe('PoliceController - Upload police case file', () => { } }) - describe('remote police call', () => { - const caseId = uuid() - const user = {} as User - const policeFileId = uuid() - const uploadPoliceCaseFile = { - id: policeFileId, - } as UploadPoliceCaseFileDto - - beforeEach(async () => { - await givenWhenThen(caseId, user, uploadPoliceCaseFile) - }) - - it('should get the police file', () => { - expect(fetch).toHaveBeenCalledWith( - expect.stringMatching( - new RegExp(`.*/GetPDFDocumentByID/${policeFileId}`), - ), - expect.anything(), - ) - }) - }) - - describe('remote AWS S3 call', () => { + describe('file uploaded to AWS S3', () => { const caseId = uuid() - const user = {} as User + const user = { id: uuid() } as User const policeFileId = uuid() const fileName = 'test.txt' const uploadPoliceCaseFile = { id: policeFileId, name: fileName, } as UploadPoliceCaseFileDto - let mockPutObject: jest.Mock + const key = uuid() + let then: Then beforeEach(async () => { - mockPutObject = mockAwsS3Service.putObject as jest.Mock const mockFetch = fetch as jest.Mock mockFetch.mockResolvedValueOnce({ ok: true, json: () => Base64.btoa('Test content'), }) - - await givenWhenThen(caseId, user, uploadPoliceCaseFile) + const mockPutObject = mockAwsS3Service.putObject as jest.Mock + mockPutObject.mockResolvedValueOnce(key) + + then = await givenWhenThen( + caseId, + CaseType.CUSTODY, + CaseState.DRAFT, + user, + uploadPoliceCaseFile, + ) }) it('should updload the file to ASW S3', () => { - expect(mockPutObject).toHaveBeenCalledWith( - expect.stringMatching(new RegExp(`^uploads/${caseId}/.{36}/test.txt$`)), + expect(fetch).toHaveBeenCalledWith( + expect.stringMatching( + new RegExp(`.*/GetPDFDocumentByID/${policeFileId}`), + ), + expect.anything(), + ) + expect(mockAwsS3Service.putObject).toHaveBeenCalledWith( + CaseType.CUSTODY, + CaseState.DRAFT, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), 'Test content', ) + expect(then.result).toEqual({ + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), + size: 12, + }) }) }) - describe('file uploaded to AWS S3', () => { + describe('indictment case file uploaded to AWS S3', () => { const caseId = uuid() - const user = {} as User + const user = { id: uuid() } as User const policeFileId = uuid() const fileName = 'test.txt' const uploadPoliceCaseFile = { id: policeFileId, name: fileName, } as UploadPoliceCaseFileDto + const key = uuid() let then: Then beforeEach(async () => { @@ -122,15 +130,33 @@ describe('PoliceController - Upload police case file', () => { ok: true, json: () => Base64.btoa('Test content'), }) - - then = await givenWhenThen(caseId, user, uploadPoliceCaseFile) + const mockPutObject = mockAwsS3Service.putObject as jest.Mock + mockPutObject.mockResolvedValueOnce(key) + + then = await givenWhenThen( + caseId, + CaseType.INDICTMENT, + CaseState.DRAFT, + user, + uploadPoliceCaseFile, + ) }) it('should updload the file to ASW S3', () => { - expect(then.result).toEqual({ - key: expect.stringMatching( - new RegExp(`^uploads/${caseId}/.{36}/test.txt$`), + expect(fetch).toHaveBeenCalledWith( + expect.stringMatching( + new RegExp(`.*/GetPDFDocumentByID/${policeFileId}`), ), + expect.anything(), + ) + expect(mockAwsS3Service.putObject).toHaveBeenCalledWith( + CaseType.INDICTMENT, + CaseState.DRAFT, + expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), + 'Test content', + ) + expect(then.result).toEqual({ + key: expect.stringMatching(new RegExp(`^${caseId}/.{36}/test.txt$`)), size: 12, }) }) @@ -146,10 +172,13 @@ describe('PoliceController - Upload police case file', () => { let then: Then beforeEach(async () => { - const mockFetch = fetch as jest.Mock - mockFetch.mockRejectedValueOnce(new Error('Some error')) - - then = await givenWhenThen(caseId, user, uploadPoliceCaseFile) + then = await givenWhenThen( + caseId, + CaseType.BANKING_SECRECY_WAIVER, + CaseState.NEW, + user, + uploadPoliceCaseFile, + ) }) it('should throw bad gateway exception', () => { @@ -173,7 +202,13 @@ describe('PoliceController - Upload police case file', () => { const mockFetch = fetch as jest.Mock mockFetch.mockResolvedValueOnce({ ok: false, text: () => 'Some error' }) - then = await givenWhenThen(caseId, user, policeCaseFile) + then = await givenWhenThen( + caseId, + CaseType.SEARCH_WARRANT, + CaseState.NEW, + user, + policeCaseFile, + ) }) it('should throw not found exception', () => { @@ -199,10 +234,14 @@ describe('PoliceController - Upload police case file', () => { ok: true, json: () => Base64.btoa('Test content'), }) - const mockPutObject = mockAwsS3Service.putObject as jest.Mock - mockPutObject.mockRejectedValueOnce(new Error('Some error')) - then = await givenWhenThen(caseId, user, uploadPoliceCaseFile) + then = await givenWhenThen( + caseId, + CaseType.TELECOMMUNICATIONS, + CaseState.NEW, + user, + uploadPoliceCaseFile, + ) }) it('should throw error', () => { diff --git a/apps/judicial-system/backend/src/app/modules/user/test/create.spec.ts b/apps/judicial-system/backend/src/app/modules/user/test/create.spec.ts index b68210ae4bc1..ecd82c585d5e 100644 --- a/apps/judicial-system/backend/src/app/modules/user/test/create.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/user/test/create.spec.ts @@ -60,7 +60,7 @@ describe('UserController - Create', () => { beforeEach(async () => { const mockCreate = mockUserModel.create as jest.Mock - mockCreate.mockReturnValueOnce(user) + mockCreate.mockResolvedValueOnce(user) then = await givenWhenThen() }) diff --git a/apps/judicial-system/backend/src/app/modules/user/test/getAll.spec.ts b/apps/judicial-system/backend/src/app/modules/user/test/getAll.spec.ts index 0e917132a8d0..22061c678711 100644 --- a/apps/judicial-system/backend/src/app/modules/user/test/getAll.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/user/test/getAll.spec.ts @@ -41,7 +41,7 @@ describe('UserController - Get all', () => { beforeEach(async () => { const mockFindAll = mockUserModel.findAll as jest.Mock - mockFindAll.mockReturnValueOnce(users) + mockFindAll.mockResolvedValueOnce(users) then = await givenWhenThen(UserRole.ADMIN) }) @@ -63,7 +63,7 @@ describe('UserController - Get all', () => { beforeEach(async () => { const mockFindAll = mockUserModel.findAll as jest.Mock - mockFindAll.mockReturnValueOnce(users) + mockFindAll.mockResolvedValueOnce(users) then = await givenWhenThen(role) }) diff --git a/apps/judicial-system/backend/src/app/modules/user/test/getById.spec.ts b/apps/judicial-system/backend/src/app/modules/user/test/getById.spec.ts index e305a7b0a81b..2dc4a5bf1bce 100644 --- a/apps/judicial-system/backend/src/app/modules/user/test/getById.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/user/test/getById.spec.ts @@ -40,7 +40,7 @@ describe('UserController - Get by id', () => { beforeEach(async () => { const mockFindByPk = mockUserModel.findByPk as jest.Mock - mockFindByPk.mockReturnValueOnce(user) + mockFindByPk.mockResolvedValueOnce(user) then = await givenWhenThen() }) diff --git a/apps/judicial-system/backend/src/app/modules/user/test/getByNationalId.spec.ts b/apps/judicial-system/backend/src/app/modules/user/test/getByNationalId.spec.ts index 4cf7312774fe..ddffe11c09b7 100644 --- a/apps/judicial-system/backend/src/app/modules/user/test/getByNationalId.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/user/test/getByNationalId.spec.ts @@ -74,7 +74,7 @@ describe('UserController - Get by national id', () => { beforeEach(async () => { const mockFindOne = mockUserModel.findOne as jest.Mock - mockFindOne.mockReturnValueOnce(user) + mockFindOne.mockResolvedValueOnce(user) then = await givenWhenThen(nationalId) }) diff --git a/apps/judicial-system/backend/src/app/modules/user/test/update.spec.ts b/apps/judicial-system/backend/src/app/modules/user/test/update.spec.ts index 9cbadfc6d3dc..ff4c56e73cc6 100644 --- a/apps/judicial-system/backend/src/app/modules/user/test/update.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/user/test/update.spec.ts @@ -42,9 +42,9 @@ describe('UserController - Update', () => { beforeEach(async () => { const mockUpdate = mockUserModel.update as jest.Mock - mockUpdate.mockReturnValueOnce([1]) + mockUpdate.mockResolvedValueOnce([1]) const mockFindByPk = mockUserModel.findByPk as jest.Mock - mockFindByPk.mockReturnValueOnce(user) + mockFindByPk.mockResolvedValueOnce(user) then = await givenWhenThen() }) diff --git a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx index ec0833e1f0ef..675bfd8a3d58 100644 --- a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx +++ b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx @@ -6,6 +6,7 @@ import { Box, Text } from '@island.is/island-ui/core' import { isCompletedCase, isDistrictCourtUser, + isTrafficViolationCase, } from '@island.is/judicial-system/types' import { FileNotFoundModal, @@ -19,7 +20,6 @@ import { } from '@island.is/judicial-system-web/src/graphql/schema' import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import { useFileList } from '@island.is/judicial-system-web/src/utils/hooks' -import { isTrafficViolationIndictment } from '@island.is/judicial-system-web/src/utils/stepHelper' import { caseFiles } from '../../routes/Prosecutor/Indictments/CaseFiles/CaseFiles.strings' import { strings } from './IndictmentCaseFilesList.strings' @@ -65,8 +65,7 @@ const IndictmentCaseFilesList: React.FC> = ( caseId: workingCase.id, }) - const showTrafficViolationCaseFiles = - isTrafficViolationIndictment(workingCase) + const showTrafficViolationCaseFiles = isTrafficViolationCase(workingCase) const cf = workingCase.caseFiles @@ -79,9 +78,6 @@ const IndictmentCaseFilesList: React.FC> = ( const criminalRecords = cf?.filter( (file) => file.category === CaseFileCategory.CRIMINAL_RECORD, ) - const criminalRecordUpdates = cf?.filter( - (file) => file.category === CaseFileCategory.CRIMINAL_RECORD_UPDATE, - ) const costBreakdowns = cf?.filter( (file) => file.category === CaseFileCategory.COST_BREAKDOWN, ) diff --git a/apps/judicial-system/web/src/routes/CourtOfAppeal/components/CaseOverviewHeader/CaseOverviewHeader.tsx b/apps/judicial-system/web/src/routes/CourtOfAppeal/components/CaseOverviewHeader/CaseOverviewHeader.tsx index fa35c4f32bb1..194f9abe61db 100644 --- a/apps/judicial-system/web/src/routes/CourtOfAppeal/components/CaseOverviewHeader/CaseOverviewHeader.tsx +++ b/apps/judicial-system/web/src/routes/CourtOfAppeal/components/CaseOverviewHeader/CaseOverviewHeader.tsx @@ -87,8 +87,8 @@ const CaseOverviewHeader: React.FC = (props) => { )} {workingCase.appealRulingDecision && - workingCase.eventLogs && - workingCase.eventLogs.length > 0 && ( + filteredEvents && + filteredEvents.length > 0 && ( {filteredEvents?.map((event, index) => ( diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/CaseFiles/CaseFiles.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/CaseFiles/CaseFiles.tsx index e0fd7ef80491..9e1593cde7a5 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/CaseFiles/CaseFiles.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/CaseFiles/CaseFiles.tsx @@ -5,6 +5,7 @@ import router from 'next/router' import { Box, InputFileUpload, Text } from '@island.is/island-ui/core' import { fileExtensionWhitelist } from '@island.is/island-ui/core/types' import * as constants from '@island.is/judicial-system/consts' +import { isTrafficViolationCase } from '@island.is/judicial-system/types' import { titles } from '@island.is/judicial-system-web/messages' import { FormContentContainer, @@ -21,7 +22,6 @@ import { useS3Upload, useUploadFiles, } from '@island.is/judicial-system-web/src/utils/hooks' -import { isTrafficViolationIndictment } from '@island.is/judicial-system-web/src/utils/stepHelper' import * as strings from './CaseFiles.strings' @@ -40,7 +40,7 @@ const CaseFiles: React.FC> = () => { workingCase.id, ) - const isTrafficViolationCaseCheck = isTrafficViolationIndictment(workingCase) + const isTrafficViolationCaseCheck = isTrafficViolationCase(workingCase) const stepIsValid = uploadFiles.some( diff --git a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx index 52911b704d7c..21f06fa7cff9 100644 --- a/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx +++ b/apps/judicial-system/web/src/routes/Prosecutor/Indictments/Processing/Processing.tsx @@ -4,6 +4,7 @@ import { useRouter } from 'next/router' import { Box, RadioButton, Text } from '@island.is/island-ui/core' import * as constants from '@island.is/judicial-system/consts' +import { isTrafficViolationCase } from '@island.is/judicial-system/types' import { titles } from '@island.is/judicial-system-web/messages' import { BlueBox, @@ -27,7 +28,6 @@ import { useCase, useDefendants, } from '@island.is/judicial-system-web/src/utils/hooks' -import { isTrafficViolationIndictment } from '@island.is/judicial-system-web/src/utils/stepHelper' import { isProcessingStepValidIndictments } from '@island.is/judicial-system-web/src/utils/validate' import { ProsecutorSection, SelectCourt } from '../../components' @@ -41,7 +41,7 @@ const Processing: React.FC = () => { const { formatMessage } = useIntl() const { updateDefendant, updateDefendantState } = useDefendants() const router = useRouter() - const isTrafficViolationCaseCheck = isTrafficViolationIndictment(workingCase) + const isTrafficViolationCaseCheck = isTrafficViolationCase(workingCase) const handleNavigationTo = useCallback( async (destination: string) => { diff --git a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx index 6b8899dcae03..584ebf057085 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx +++ b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx @@ -18,6 +18,7 @@ import { isInvestigationCase, isPublicProsecutorUser, isRestrictionCase, + isTrafficViolationCase, } from '@island.is/judicial-system/types' import { errors } from '@island.is/judicial-system-web/messages' import { UserContext } from '@island.is/judicial-system-web/src/components' @@ -30,7 +31,6 @@ import { import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import { findFirstInvalidStep } from '../../formHelper' -import { isTrafficViolationIndictment } from '../../stepHelper' import useCase from '../useCase' const useCaseList = () => { @@ -74,7 +74,7 @@ const useCaseList = () => { const openCase = (caseToOpen: Case, user: User) => { let routeTo = null - const isTrafficViolation = isTrafficViolationIndictment(caseToOpen) + const isTrafficViolation = isTrafficViolationCase(caseToOpen) if (isDefenceUser(user)) { if (isIndictmentCase(caseToOpen.type)) { diff --git a/apps/judicial-system/web/src/utils/hooks/useS3Upload/createPresignedPost.graphql b/apps/judicial-system/web/src/utils/hooks/useS3Upload/createPresignedPost.graphql index 7bb7c7702cea..4f3ded8599bc 100644 --- a/apps/judicial-system/web/src/utils/hooks/useS3Upload/createPresignedPost.graphql +++ b/apps/judicial-system/web/src/utils/hooks/useS3Upload/createPresignedPost.graphql @@ -2,5 +2,6 @@ mutation CreatePresignedPost($input: CreatePresignedPostInput!) { createPresignedPost(input: $input) { url fields + key } } diff --git a/apps/judicial-system/web/src/utils/hooks/useS3Upload/limitedAccessCreatePresignedPost.graphql b/apps/judicial-system/web/src/utils/hooks/useS3Upload/limitedAccessCreatePresignedPost.graphql index d578f36b3aaa..b334cc70d5ac 100644 --- a/apps/judicial-system/web/src/utils/hooks/useS3Upload/limitedAccessCreatePresignedPost.graphql +++ b/apps/judicial-system/web/src/utils/hooks/useS3Upload/limitedAccessCreatePresignedPost.graphql @@ -2,5 +2,6 @@ mutation LimitedAccessCreatePresignedPost($input: CreatePresignedPostInput!) { limitedAccessCreatePresignedPost(input: $input) { url fields + key } } diff --git a/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts b/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts index 572bc62bd1b8..9580d95bfe8a 100644 --- a/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts +++ b/apps/judicial-system/web/src/utils/hooks/useS3Upload/useS3Upload.ts @@ -267,7 +267,7 @@ const useS3Upload = (caseId: string) => { return presignedPost } - const promises = files.map(async (file, idx) => { + const promises = files.map(async (file) => { try { updateFile({ ...file, status: 'uploading' }) @@ -279,13 +279,13 @@ const useS3Upload = (caseId: string) => { const newFileId = await addFileToCaseState({ ...file, - key: presignedPost.fields.key, + key: presignedPost.key, }) updateFile( { ...file, - key: presignedPost.fields.key, + key: presignedPost.key, percent: 100, status: 'done', }, diff --git a/apps/judicial-system/web/src/utils/hooks/useSections/index.ts b/apps/judicial-system/web/src/utils/hooks/useSections/index.ts index 7ee6ca835c9c..8d0c0f1363ff 100644 --- a/apps/judicial-system/web/src/utils/hooks/useSections/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useSections/index.ts @@ -15,6 +15,7 @@ import { isInvestigationCase, isProsecutionUser, isRestrictionCase, + isTrafficViolationCase, } from '@island.is/judicial-system/types' import { core, sections } from '@island.is/judicial-system-web/messages' import { RouteSection } from '@island.is/judicial-system-web/src/components/PageLayout/PageLayout' @@ -30,10 +31,7 @@ import { import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import { stepValidations, stepValidationsType } from '../../formHelper' -import { - isTrafficViolationIndictment, - shouldUseAppealWithdrawnRoutes, -} from '../../stepHelper' +import { shouldUseAppealWithdrawnRoutes } from '../../stepHelper' const validateFormStepper = ( isActiveSubSectionValid: boolean, @@ -401,7 +399,7 @@ const useSections = ( const { id, type, state } = workingCase const caseHasBeenReceivedByCourt = state === CaseState.RECEIVED || state === CaseState.MAIN_HEARING - const isTrafficViolation = isTrafficViolationIndictment(workingCase) + const isTrafficViolation = isTrafficViolationCase(workingCase) return { name: formatMessage(sections.indictmentCaseProsecutorSection.title), diff --git a/apps/judicial-system/web/src/utils/stepHelper.ts b/apps/judicial-system/web/src/utils/stepHelper.ts index 50f0a8bb8abe..e410eac190bb 100644 --- a/apps/judicial-system/web/src/utils/stepHelper.ts +++ b/apps/judicial-system/web/src/utils/stepHelper.ts @@ -3,12 +3,9 @@ import parseISO from 'date-fns/parseISO' import { TagVariant } from '@island.is/island-ui/core' import { formatDate } from '@island.is/judicial-system/formatters' -import { isTrafficViolationCase } from '@island.is/judicial-system/types' import { CaseAppealState, CaseCustodyRestrictions, - CaseFileCategory, - CaseType, DefendantPlea, Gender, Notification, @@ -89,23 +86,6 @@ export const createCaseResentExplanation = ( }Krafa endursend ${formatDate(now, 'PPPp')} - ${explanation}` } -export const isTrafficViolationIndictment = (workingCase: Case): boolean => { - const isTrafficViolation = isTrafficViolationCase( - workingCase.indictmentSubtypes, - workingCase.type as CaseType, - ) - - return Boolean( - isTrafficViolation && - !( - workingCase.caseFiles && - workingCase.caseFiles.find( - (file) => file.category === CaseFileCategory.INDICTMENT, - ) - ), - ) -} - export const hasSentNotification = ( notificationType: NotificationType, notifications?: Notification[] | null, diff --git a/apps/judicial-system/web/src/utils/validate.ts b/apps/judicial-system/web/src/utils/validate.ts index 13e371364c45..574b11f7b2f2 100644 --- a/apps/judicial-system/web/src/utils/validate.ts +++ b/apps/judicial-system/web/src/utils/validate.ts @@ -1,6 +1,7 @@ // TODO: Add tests import { isIndictmentCase, + isTrafficViolationCase, prosecutorCanSelectDefenderForInvestigationCase, } from '@island.is/judicial-system/types' import { @@ -13,7 +14,7 @@ import { } from '@island.is/judicial-system-web/src/graphql/schema' import { TempCase as Case } from '@island.is/judicial-system-web/src/types' -import { isBusiness, isTrafficViolationIndictment } from './stepHelper' +import { isBusiness } from './stepHelper' export type Validation = | 'empty' @@ -495,7 +496,7 @@ export const isCaseFilesStepValidIndictments = (workingCase: Case): boolean => { workingCase.caseFiles?.some( (file) => file.category === CaseFileCategory.COVER_LETTER, ) && - (isTrafficViolationIndictment(workingCase) || + (isTrafficViolationCase(workingCase) || workingCase.caseFiles?.some( (file) => file.category === CaseFileCategory.INDICTMENT, )) && diff --git a/libs/judicial-system/message/src/lib/message.ts b/libs/judicial-system/message/src/lib/message.ts index 25b8a19fe439..6af02e86d5de 100644 --- a/libs/judicial-system/message/src/lib/message.ts +++ b/libs/judicial-system/message/src/lib/message.ts @@ -3,6 +3,7 @@ import type { User } from '@island.is/judicial-system/types' export enum MessageType { DELIVERY_TO_COURT_PROSECUTOR = 'DELIVERY_TO_COURT_PROSECUTOR', DELIVERY_TO_COURT_DEFENDANT = 'DELIVERY_TO_COURT_DEFENDANT', + DELIVERY_TO_COURT_INDICTMENT = 'DELIVERY_TO_COURT_INDICTMENT', DELIVERY_TO_COURT_CASE_FILE = 'DELIVERY_TO_COURT_CASE_FILE', DELIVERY_TO_COURT_CASE_FILES_RECORD = 'DELIVERY_TO_COURT_CASE_FILES_RECORD', DELIVERY_TO_COURT_REQUEST = 'DELIVERY_TO_COURT_REQUEST', @@ -21,12 +22,14 @@ export enum MessageType { DELIVERY_TO_POLICE_APPEAL = 'DELIVERY_TO_POLICE_APPEAL', ARCHIVING_CASE_FILE = 'ARCHIVING_CASE_FILE', ARCHIVING_CASE_FILES_RECORD = 'ARCHIVING_CASE_FILES_RECORD', + // TODO: Archive confirmted generated indictments NOTIFICATION = 'NOTIFICATION', } export const messageEndpoint: { [key in MessageType]: string } = { DELIVERY_TO_COURT_PROSECUTOR: 'deliverProsecutorToCourt', DELIVERY_TO_COURT_DEFENDANT: 'deliverDefendantToCourt', + DELIVERY_TO_COURT_INDICTMENT: 'deliverIndictmentToCourt', DELIVERY_TO_COURT_CASE_FILE: 'deliverCaseFileToCourt', DELIVERY_TO_COURT_CASE_FILES_RECORD: 'deliverCaseFilesRecordToCourt', DELIVERY_TO_COURT_REQUEST: 'deliverRequestToCourt', diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 2e9249225945..c7b78aa76a00 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -65,6 +65,7 @@ export { completedIndictmentCaseStates, completedCaseStates, isCompletedCase, + hasIndictmentCaseBeenSubmittedToCourt, getStatementDeadline, prosecutorCanSelectDefenderForInvestigationCase, isIndictmentCaseState, @@ -76,7 +77,6 @@ export type { CrimeScene, CrimeSceneMap, IndictmentSubtypeMap, - IndictmentConfirmation, } from './lib/case' export { diff --git a/libs/judicial-system/types/src/lib/case.ts b/libs/judicial-system/types/src/lib/case.ts index 64aaaf215897..48cc5afc3bff 100644 --- a/libs/judicial-system/types/src/lib/case.ts +++ b/libs/judicial-system/types/src/lib/case.ts @@ -1,5 +1,7 @@ import flatten from 'lodash/flatten' +import { CaseFileCategory } from './file' + export enum CaseOrigin { UNKNOWN = 'UNKNOWN', RVG = 'RVG', @@ -310,7 +312,6 @@ export const acceptedCaseDecisions = [ CaseDecision.ACCEPTING_PARTIALLY, ] -// TODO: Move to the client as it is only used there export const isAcceptingCaseDecision = ( decision?: CaseDecision | null, ): boolean => { @@ -333,21 +334,44 @@ export const isCompletedCase = (state?: CaseState | null): boolean => { return Boolean(state && completedCaseStates.includes(state)) } -export const isTrafficViolationCase = ( - indictmentSubtypes?: IndictmentSubtypeMap, - type?: CaseType, +export const hasIndictmentCaseBeenSubmittedToCourt = ( + state?: CaseState | null, ): boolean => { - if (!indictmentSubtypes || type !== CaseType.INDICTMENT) { + return Boolean( + state && + [ + CaseState.SUBMITTED, + CaseState.RECEIVED, + CaseState.MAIN_HEARING, + ...completedIndictmentCaseStates, + ].includes(state), + ) +} + +export const isTrafficViolationCase = (theCase: { + type?: CaseType | null + indictmentSubtypes?: IndictmentSubtypeMap + caseFiles?: { category?: CaseFileCategory | null }[] | null +}): boolean => { + if ( + theCase.type !== CaseType.INDICTMENT || + !theCase.indictmentSubtypes || + theCase.caseFiles?.some( + (file) => file.category === CaseFileCategory.INDICTMENT, + ) + ) { return false } - const flatIndictmentSubtypes = flatten(Object.values(indictmentSubtypes)) + const flatIndictmentSubtypes = flatten( + Object.values(theCase.indictmentSubtypes), + ) - return Boolean( + return ( flatIndictmentSubtypes.length > 0 && - flatIndictmentSubtypes.every( - (val) => val === IndictmentSubtype.TRAFFIC_VIOLATION, - ), + flatIndictmentSubtypes.every( + (val) => val === IndictmentSubtype.TRAFFIC_VIOLATION, + ) ) } @@ -403,7 +427,3 @@ export const isRequestCaseTransition = ( transition as RequestCaseTransition, ) } - -export type IndictmentConfirmation = - | { actor: string; institution: string; date: Date } - | undefined From cf2f7ea141299c7ea2d3dc2760aadd0f28141bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9tur=20Neisti=20Erlingsson?= Date: Wed, 29 May 2024 15:27:26 +0000 Subject: [PATCH 04/82] fix: init dd-trace with node (#14972) * fix: init dd-trace with node * chore: charts update dirty files --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- charts/identity-server/values.dev.yaml | 18 ++--- charts/identity-server/values.prod.yaml | 18 ++--- charts/identity-server/values.staging.yaml | 18 ++--- charts/islandis/values.dev.yaml | 72 +++++++++---------- charts/islandis/values.prod.yaml | 68 +++++++++--------- charts/islandis/values.staging.yaml | 64 ++++++++--------- charts/judicial-system/values.dev.yaml | 16 ++--- charts/judicial-system/values.prod.yaml | 16 ++--- charts/judicial-system/values.staging.yaml | 16 ++--- infra/src/dsl/basic.spec.ts | 2 +- infra/src/dsl/feature-values.spec.ts | 2 +- .../output-generators/map-to-helm-values.ts | 2 +- infra/src/dsl/postgres.spec.ts | 2 +- 13 files changed, 157 insertions(+), 157 deletions(-) diff --git a/charts/identity-server/values.dev.yaml b/charts/identity-server/values.dev.yaml index 11448bc333ac..9f9bb6685b83 100644 --- a/charts/identity-server/values.dev.yaml +++ b/charts/identity-server/values.dev.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.dev01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.dev01.devland.is","https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -627,7 +627,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -698,7 +698,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/identity-server/values.prod.yaml b/charts/identity-server/values.prod.yaml index f1eb83b1f8da..7c68d1aa4457 100644 --- a/charts/identity-server/values.prod.yaml +++ b/charts/identity-server/values.prod.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://innskra.island.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -112,7 +112,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'https://service-portal-api.internal.island.is' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'true' PersistenceSettings__SessionsBaseAddress: 'https://sessions-api.internal.island.is' @@ -217,7 +217,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -285,7 +285,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' USER_NOTIFICATION_API_URL: 'https://user-notification.internal.island.is' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -372,7 +372,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -487,7 +487,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -542,7 +542,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -616,7 +616,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -687,7 +687,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/identity-server/values.staging.yaml b/charts/identity-server/values.staging.yaml index c495716079b6..fa80d892debd 100644 --- a/charts/identity-server/values.staging.yaml +++ b/charts/identity-server/values.staging.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.staging01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -619,7 +619,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -690,7 +690,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index f9e8ac904fef..0d5633e3742d 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.dev01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -599,7 +599,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -814,7 +814,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -899,7 +899,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_PATH: '' @@ -972,7 +972,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.dev01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1033,7 +1033,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1097,7 +1097,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1165,7 +1165,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1280,7 +1280,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1371,7 +1371,7 @@ external-contracts-tests: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1433,7 +1433,7 @@ github-actions-cache: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_NODES: 'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] @@ -1514,7 +1514,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1599,7 +1599,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -1660,7 +1660,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1778,7 +1778,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' @@ -1847,7 +1847,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1943,7 +1943,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -2068,7 +2068,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2150,7 +2150,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2277,7 +2277,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2353,7 +2353,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2431,7 +2431,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2502,7 +2502,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2565,7 +2565,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2659,7 +2659,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2788,7 +2788,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2863,7 +2863,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2933,7 +2933,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -3043,7 +3043,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3134,7 +3134,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -3238,7 +3238,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3336,7 +3336,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.dev01.devland.is' grantNamespaces: @@ -3408,7 +3408,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 600f523374fd..7feb51773a83 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -90,7 +90,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -194,7 +194,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.island.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -303,7 +303,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'island@island.is' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -589,7 +589,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'island@island.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Stafrænt Ísland' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Production' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -804,7 +804,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -889,7 +889,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_PATH: '' @@ -965,7 +965,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://island.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1029,7 +1029,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1092,7 +1092,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1160,7 +1160,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS/EDU/4112043590/LBHI-Protected/brautskraning-v1' @@ -1275,7 +1275,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1382,7 +1382,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -1467,7 +1467,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -1527,7 +1527,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1643,7 +1643,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' @@ -1715,7 +1715,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1811,7 +1811,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1936,7 +1936,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2021,7 +2021,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2148,7 +2148,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2224,7 +2224,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -2302,7 +2302,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2373,7 +2373,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -2436,7 +2436,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2530,7 +2530,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2659,7 +2659,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2734,7 +2734,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -2807,7 +2807,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'application-system' @@ -2920,7 +2920,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3011,7 +3011,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -3115,7 +3115,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3213,7 +3213,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TRACKING_DOMAIN: 'island.is' grantNamespaces: @@ -3289,7 +3289,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index a9f2d39d7529..e5900abff5fd 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.staging01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -597,7 +597,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -812,7 +812,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -897,7 +897,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_PATH: '' @@ -971,7 +971,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.staging01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1035,7 +1035,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1151,7 +1151,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1258,7 +1258,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1343,7 +1343,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -1404,7 +1404,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1519,7 +1519,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' @@ -1589,7 +1589,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1685,7 +1685,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1810,7 +1810,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -1893,7 +1893,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2020,7 +2020,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2096,7 +2096,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2174,7 +2174,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2245,7 +2245,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2308,7 +2308,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2402,7 +2402,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2531,7 +2531,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2606,7 +2606,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2676,7 +2676,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -2786,7 +2786,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -2877,7 +2877,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2981,7 +2981,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3080,7 +3080,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.staging01.devland.is' grantNamespaces: @@ -3152,7 +3152,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index c20aacc92019..8d670725811a 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' S3_BUCKET: 'island-is-dev-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.dev01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index 3a9c94c20cd8..2e9c2f0aadc8 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://ws.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-prod-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://rettarvorslugatt.island.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index f93fd2f7c445..3cb6162b7289 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-staging-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.staging01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/infra/src/dsl/basic.spec.ts b/infra/src/dsl/basic.spec.ts index e4201e50236e..f3d24bb8d736 100644 --- a/infra/src/dsl/basic.spec.ts +++ b/infra/src/dsl/basic.spec.ts @@ -103,7 +103,7 @@ describe('Basic serialization', () => { DB_NAME: 'api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=460', + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) diff --git a/infra/src/dsl/feature-values.spec.ts b/infra/src/dsl/feature-values.spec.ts index eba9a6d3cf28..9ee13cb2f03d 100644 --- a/infra/src/dsl/feature-values.spec.ts +++ b/infra/src/dsl/feature-values.spec.ts @@ -94,7 +94,7 @@ describe('Feature-deployment support', () => { DB_NAME: 'feature_feature_A_graphql', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230', + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', DB_EXTENSIONS: 'foo', diff --git a/infra/src/dsl/output-generators/map-to-helm-values.ts b/infra/src/dsl/output-generators/map-to-helm-values.ts index 7bead10451ff..786140c04abf 100644 --- a/infra/src/dsl/output-generators/map-to-helm-values.ts +++ b/infra/src/dsl/output-generators/map-to-helm-values.ts @@ -60,7 +60,7 @@ const serializeService: SerializeMethod = async ( SERVERSIDE_FEATURES_ON: env1.featuresOn.join(','), NODE_OPTIONS: `--max-old-space-size=${getScaledValue( serviceDef.resources.limits.memory, - )}`, + )} -r dd-trace/init`, LOG_LEVEL: 'info', }, secrets: {}, diff --git a/infra/src/dsl/postgres.spec.ts b/infra/src/dsl/postgres.spec.ts index ddb7d0753888..7c7e73c68652 100644 --- a/infra/src/dsl/postgres.spec.ts +++ b/infra/src/dsl/postgres.spec.ts @@ -41,7 +41,7 @@ describe('Postgres', () => { DB_NAME: 'service_portal_api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230', + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) From 302a1c0be8063cc1aea1583262d50afc9f3944ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Wed, 29 May 2024 15:50:28 +0000 Subject: [PATCH 05/82] fix(j-s): District Court Routing (#14956) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../web/src/utils/hooks/useCaseList/index.tsx | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx index 584ebf057085..7fa6495fb7f3 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx +++ b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx @@ -84,18 +84,6 @@ const useCaseList = () => { } } else if (isPublicProsecutorUser(user)) { routeTo = constants.PUBLIC_PROSECUTOR_STAFF_INDICTMENT_OVERVIEW_ROUTE - } else if (isCompletedCase(caseToOpen.state)) { - if (isIndictmentCase(caseToOpen.type)) { - routeTo = constants.CLOSED_INDICTMENT_OVERVIEW_ROUTE - } else if (isCourtOfAppealsUser(user)) { - if (caseToOpen.appealState === CaseAppealState.COMPLETED) { - routeTo = constants.COURT_OF_APPEAL_RESULT_ROUTE - } else { - routeTo = constants.COURT_OF_APPEAL_OVERVIEW_ROUTE - } - } else { - routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE - } } else if (isDistrictCourtUser(user)) { if (isRestrictionCase(caseToOpen.type)) { routeTo = findFirstInvalidStep( @@ -112,6 +100,18 @@ const useCaseList = () => { // would be skipped if we route to the last valid step routeTo = constants.INDICTMENTS_COURT_OVERVIEW_ROUTE } + } else if (isCompletedCase(caseToOpen.state)) { + if (isIndictmentCase(caseToOpen.type)) { + routeTo = constants.CLOSED_INDICTMENT_OVERVIEW_ROUTE + } else if (isCourtOfAppealsUser(user)) { + if (caseToOpen.appealState === CaseAppealState.COMPLETED) { + routeTo = constants.COURT_OF_APPEAL_RESULT_ROUTE + } else { + routeTo = constants.COURT_OF_APPEAL_OVERVIEW_ROUTE + } + } else { + routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE + } } else { if (isRestrictionCase(caseToOpen.type)) { routeTo = findFirstInvalidStep( @@ -162,6 +162,7 @@ const useCaseList = () => { ? getLimitedAccessCase({ variables: { input: { id } } }) : getCase({ variables: { input: { id } } }) } + if ( isTransitioningCase || isSendingNotification || From 3bf1b64ce3a76fb30a0a4ef4b0d9b5a1c46b5980 Mon Sep 17 00:00:00 2001 From: veronikasif <54938148+veronikasif@users.noreply.github.com> Date: Wed, 29 May 2024 15:57:28 +0000 Subject: [PATCH 06/82] feat(ui-fields): Add max rows to TableRepeaterFormField (#15000) * Added max values to TableRepeaterFormField * Renamed to maxRows --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- libs/application/core/src/lib/fieldBuilders.ts | 2 ++ libs/application/types/src/lib/Fields.ts | 5 +++++ .../lib/TableRepeaterFormField/TableRepeaterFormField.tsx | 3 +++ 3 files changed, 10 insertions(+) diff --git a/libs/application/core/src/lib/fieldBuilders.ts b/libs/application/core/src/lib/fieldBuilders.ts index 3f85d092a381..0b44c7cf6939 100644 --- a/libs/application/core/src/lib/fieldBuilders.ts +++ b/libs/application/core/src/lib/fieldBuilders.ts @@ -745,6 +745,7 @@ export function buildTableRepeaterField( editButtonTooltipText, editField, getStaticTableData, + maxRows, } = data return { @@ -764,6 +765,7 @@ export function buildTableRepeaterField( editButtonTooltipText, editField, getStaticTableData, + maxRows, } } diff --git a/libs/application/types/src/lib/Fields.ts b/libs/application/types/src/lib/Fields.ts index c5062c48073f..47846876397b 100644 --- a/libs/application/types/src/lib/Fields.ts +++ b/libs/application/types/src/lib/Fields.ts @@ -506,6 +506,11 @@ export type TableRepeaterField = BaseField & { marginBottom?: ResponsiveProp titleVariant?: TitleVariants fields: Record + /** + * Maximum rows that can be added to the table. + * When the maximum is reached, the button to add a new row is disabled. + */ + maxRows?: number table?: { /** * List of strings to render, diff --git a/libs/application/ui-fields/src/lib/TableRepeaterFormField/TableRepeaterFormField.tsx b/libs/application/ui-fields/src/lib/TableRepeaterFormField/TableRepeaterFormField.tsx index fd211f8ef1a6..7c9aad27a2cb 100644 --- a/libs/application/ui-fields/src/lib/TableRepeaterFormField/TableRepeaterFormField.tsx +++ b/libs/application/ui-fields/src/lib/TableRepeaterFormField/TableRepeaterFormField.tsx @@ -60,6 +60,7 @@ export const TableRepeaterFormField: FC = ({ removeButtonTooltipText = coreMessages.deleteFieldText, editButtonTooltipText = coreMessages.editFieldText, editField = false, + maxRows, } = data const items = Object.keys(rawItems).map((key) => ({ @@ -82,6 +83,7 @@ export const TableRepeaterFormField: FC = ({ const tableHeader = table?.header ?? tableItems.map((item) => item.label) const tableRows = table?.rows ?? tableItems.map((item) => item.id) const staticData = getStaticTableData?.(application) + const canAddItem = maxRows ? savedFields.length < maxRows : true const handleSaveItem = async (index: number) => { const isValid = await methods.trigger(`${data.id}[${index}]`, { @@ -311,6 +313,7 @@ export const TableRepeaterFormField: FC = ({ type="button" onClick={handleNewItem} icon="add" + disabled={!canAddItem} > {formatText(addItemButtonText, application, formatMessage)} From 9e3215ec54944fa66c23a76ef3a17f572f2366ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 29 May 2024 18:33:23 +0000 Subject: [PATCH 07/82] fix(district-commissioners-licenses): update client (#14973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:init * fix:more * fix:works now --------- Co-authored-by: Þorkell Máni Þorkelsson Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../project.json | 2 +- .../src/clientConfig.json | 170 ++++++++++++++++-- .../districtCommissionersLicenses.config.ts | 4 +- .../districtCommissionersLicenses.module.ts | 2 +- .../districtCommissionersLicenses.service.ts | 4 +- 5 files changed, 157 insertions(+), 25 deletions(-) diff --git a/libs/clients/district-commissioners-licenses/project.json b/libs/clients/district-commissioners-licenses/project.json index d6bd6c75d3ee..6d4ad14cc08c 100644 --- a/libs/clients/district-commissioners-licenses/project.json +++ b/libs/clients/district-commissioners-licenses/project.json @@ -31,7 +31,7 @@ "executor": "nx:run-commands", "options": { "commands": [ - "curl https://api.syslumenn.is/staging/swagger/v1/swagger.json > src/clientConfig.json", + "curl -H \"X-Road-Client: $XROAD_CLIENT_ID\" http://localhost:8081/r1/IS-DEV/GOV/10016/Syslumenn-Protected/swagger -H 'Accept: application/json' > src/clientConfig.json", "prettier --write src/clientConfig.json" ], "parallel": false, diff --git a/libs/clients/district-commissioners-licenses/src/clientConfig.json b/libs/clients/district-commissioners-licenses/src/clientConfig.json index 5c2eb6be4614..95052de0dfe1 100644 --- a/libs/clients/district-commissioners-licenses/src/clientConfig.json +++ b/libs/clients/district-commissioners-licenses/src/clientConfig.json @@ -2001,6 +2001,52 @@ ] } }, + "/api/KannaSakavottord/{audkenni}/{kennitala}": { + "get": { + "tags": ["KannaSakavottord"], + "operationId": "KannaSakavottord_Get", + "parameters": [ + { + "type": "string", + "name": "audkenni", + "in": "path", + "required": true, + "x-nullable": false + }, + { + "type": "string", + "name": "kennitala", + "in": "path", + "required": true, + "x-nullable": false + } + ], + "responses": { + "200": { + "description": "" + }, + "401": { + "x-nullable": false, + "description": "", + "schema": { + "$ref": "#/definitions/ProblemDetails" + } + }, + "default": { + "x-nullable": false, + "description": "", + "schema": { + "$ref": "#/definitions/ProblemDetails" + } + } + }, + "security": [ + { + "JWT Token": [] + } + ] + } + }, "/api/KaupmaliJaNei/{kennitala}/{audkenni}": { "get": { "tags": ["KaupmaliJaNei"], @@ -2301,24 +2347,10 @@ ] } }, - "/api/RettindiFyrirIslandIs": { + "/RettindiFyrirIslandIs/RettindiFyrirIslandIs": { "get": { "tags": ["RettindiFyrirIslandIs"], "operationId": "RettindiFyrirIslandIs_Get", - "parameters": [ - { - "type": "string", - "name": "Kennitala", - "in": "query", - "x-nullable": true - }, - { - "type": "string", - "name": "Locale", - "in": "query", - "x-nullable": true - } - ], "responses": { "200": { "x-nullable": false, @@ -2356,7 +2388,7 @@ ] } }, - "/api/RettindiFyrirIslandIs/{audkenni}": { + "/RettindiFyrirIslandIs/RettindiFyrirIslandIs/{audkenni}": { "get": { "tags": ["RettindiFyrirIslandIs"], "operationId": "RettindiFyrirIslandIs_GetStakt", @@ -2720,6 +2752,45 @@ ] } }, + "/api/Vedbokarvottord2": { + "post": { + "tags": ["Vedbokarvottord2"], + "operationId": "Vedbokarvottord2_Post", + "consumes": ["application/json", "text/json", "application/*+json"], + "parameters": [ + { + "name": "skilabod", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/VedbandayfirlitMargirSkeyti" + }, + "x-nullable": false + } + ], + "responses": { + "200": { + "x-nullable": false, + "description": "Success", + "schema": { + "$ref": "#/definitions/VedbandayfirlitSvarSkeyti" + } + }, + "404": { + "x-nullable": false, + "description": "NotFound", + "schema": { + "$ref": "#/definitions/VedbandayfirlitSvarSkeyti" + } + } + }, + "security": [ + { + "JWT Token": [] + } + ] + } + }, "/api/Vedbokarvottord": { "post": { "tags": ["Vedbokarvottord"], @@ -2759,6 +2830,51 @@ ] } }, + "/api/Vedbokavottord2Regluverki": { + "post": { + "tags": ["Vedbokavottord2Regluverki"], + "operationId": "Vedbokavottord2Regluverki_Post", + "consumes": ["application/json", "text/json", "application/*+json"], + "parameters": [ + { + "name": "skilabod", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/VedbandayfirlitMargirSkeyti" + }, + "x-nullable": false + } + ], + "responses": { + "200": { + "x-nullable": false, + "description": "Success", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/VedbandayfirlitReguverkiSvarSkeyti" + } + } + }, + "404": { + "x-nullable": false, + "description": "NotFound", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/VedbandayfirlitReguverkiSvarSkeyti" + } + } + } + }, + "security": [ + { + "JWT Token": [] + } + ] + } + }, "/api/VedbokavottordRegluverki": { "post": { "tags": ["VedbokavottordRegluverki"], @@ -5438,7 +5554,7 @@ } } }, - "VedbandayfirlitSkeyti": { + "VedbandayfirlitMargirSkeyti": { "type": "object", "required": ["tegundAndlags"], "properties": { @@ -5446,7 +5562,10 @@ "type": "string" }, "fastanumer": { - "type": "string" + "type": "array", + "items": { + "type": "string" + } }, "tegundAndlags": { "$ref": "#/definitions/VedbondTegundAndlags" @@ -5466,6 +5585,21 @@ ], "enum": [0, 1, 2, 3, 4, 5] }, + "VedbandayfirlitSkeyti": { + "type": "object", + "required": ["tegundAndlags"], + "properties": { + "audkenni": { + "type": "string" + }, + "fastanumer": { + "type": "string" + }, + "tegundAndlags": { + "$ref": "#/definitions/VedbondTegundAndlags" + } + } + }, "VedbandayfirlitReguverkiSvarSkeyti": { "type": "object", "required": ["landNr"], diff --git a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.config.ts b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.config.ts index 704738946504..371444b91b0f 100644 --- a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.config.ts +++ b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.config.ts @@ -14,8 +14,8 @@ export const DistrictCommissionersLicensesClientConfig = defineConfig< schema, load: (env) => ({ xRoadServicePath: env.required( - 'XROAD_DISTRICT_COMMISSIONERS_LICENSES_PATH', - 'IS-DEV/GOV/10016/Syslumenn-Protected/RettindiIslandis', + 'XROAD_DISTRICT_COMMISSIONERS_P_CARD_PATH', + 'IS-DEV/GOV/10016/Syslumenn-Protected/IslandMinarSidur', ), scope: [DistrictCommissionersScope.dcLicensesScope], }), diff --git a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.module.ts b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.module.ts index e7325b7d156b..8a1b8bfbd01d 100644 --- a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.module.ts +++ b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common' -import { DistrictCommissionerLicensesApiProvider } from './districtCommissionersLicenses.provider' import { DistrictCommissionersLicensesService } from './districtCommissionersLicenses.service' import { RettindiFyrirIslandIsApi } from '../../gen/fetch' +import { DistrictCommissionerLicensesApiProvider } from './districtCommissionersLicenses.provider' @Module({ providers: [ diff --git a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.service.ts b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.service.ts index 9928c2d4d095..7cf748e68bb5 100644 --- a/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.service.ts +++ b/libs/clients/district-commissioners-licenses/src/lib/districtCommissionersLicenses.service.ts @@ -28,9 +28,7 @@ export class DistrictCommissionersLicensesService { user: User, ): Promise> { const licenseInfo = await this.apiWithAuth(user) - .rettindiFyrirIslandIsGet({ - kennitala: '0101303019', - }) + .rettindiFyrirIslandIsGet() .catch(handle404) return ( From 49c07acfcf409f1feeebf8886d7e7505b735f687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Wed, 29 May 2024 18:55:23 +0000 Subject: [PATCH 08/82] fix(ojoi): Update clientconfig + minor fixes. (#15005) * Update advert and schema for ojoi * remove console log * chore: nx format:write update dirty files --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../OfficialJournalOfIceland/OJOIUtils.ts | 5 +- .../src/lib/models/advert.input.ts | 4 +- .../lib/officialJournalOfIceland.resolver.ts | 4 +- .../lib/officialJournalOfIceland.service.ts | 6 +- .../public/src/clientConfig.json | 378 ++++++++++++++---- 5 files changed, 308 insertions(+), 89 deletions(-) diff --git a/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts b/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts index 4921ab04a0ed..0c60d31b0225 100644 --- a/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts +++ b/apps/web/components/OfficialJournalOfIceland/OJOIUtils.ts @@ -1,5 +1,6 @@ import format from 'date-fns/format' import is from 'date-fns/locale/is' +import sortBy from 'lodash/sortBy' import { StringOption as Option } from '@island.is/island-ui/core' import { sortAlpha } from '@island.is/shared/utils' @@ -54,7 +55,9 @@ export const mapEntityToOptions = ( if (!entities) { return [] } - return entities.map((e) => { + const sortedEntities = sortBy(entities, (d) => d.title.trim()) + + return sortedEntities.map((e) => { if (e.__typename === 'OfficialJournalOfIcelandAdvertCategory') { return { label: e.title, diff --git a/libs/api/domains/official-journal-of-iceland/src/lib/models/advert.input.ts b/libs/api/domains/official-journal-of-iceland/src/lib/models/advert.input.ts index 8eb8dd1df2e0..f8ed0d141546 100644 --- a/libs/api/domains/official-journal-of-iceland/src/lib/models/advert.input.ts +++ b/libs/api/domains/official-journal-of-iceland/src/lib/models/advert.input.ts @@ -30,10 +30,10 @@ export class AdvertsInput { involvedParty?: string[] @Field(() => Date, { nullable: true }) - dateFrom?: string + dateFrom?: Date @Field(() => Date, { nullable: true }) - dateTo?: string + dateTo?: Date } @InputType('OfficialJournalOfIcelandTypesInput') diff --git a/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.resolver.ts b/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.resolver.ts index c1a66116d847..da42d2c9c562 100644 --- a/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.resolver.ts +++ b/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.resolver.ts @@ -38,9 +38,7 @@ export class OfficialJournalOfIcelandResolver { name: 'officialJournalOfIcelandAdverts', }) adverts(@Args('input') input: AdvertsInput) { - return this.ojoiService.adverts({ - search: input.search, - }) + return this.ojoiService.adverts(input) } @Query(() => AdvertDepartmentResponse, { diff --git a/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.service.ts b/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.service.ts index b1b1b3a9e1e6..4c4a132b079d 100644 --- a/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.service.ts +++ b/libs/api/domains/official-journal-of-iceland/src/lib/officialJournalOfIceland.service.ts @@ -48,11 +48,11 @@ export class OfficialJournalOfIcelandService { } async advert(params: AdvertQueryParams): Promise { - const data = await this.ojoiService.advert(params) + const { advert } = await this.ojoiService.advert(params) return { advert: { - ...data, - status: mapAdvertStatus(data.status), + ...advert, + status: mapAdvertStatus(advert.status), }, } } diff --git a/libs/clients/official-journal-of-iceland/public/src/clientConfig.json b/libs/clients/official-journal-of-iceland/public/src/clientConfig.json index 8577fe74c254..773d0c46245b 100644 --- a/libs/clients/official-journal-of-iceland/public/src/clientConfig.json +++ b/libs/clients/official-journal-of-iceland/public/src/clientConfig.json @@ -1,15 +1,18 @@ { "openapi": "3.0.0", "paths": { - "/api/v1/advert": { + "/api/v1/adverts/{id}": { "get": { "operationId": "JournalController_advert", "parameters": [ { "name": "id", "required": true, - "in": "query", - "schema": { "type": "string" } + "in": "path", + "description": "Advert ID.", + "schema": { + "type": "string" + } } ], "responses": { @@ -17,7 +20,9 @@ "description": "Advert by ID.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/Advert" } + "schema": { + "$ref": "#/components/schemas/GetAdvertResponse" + } } } }, @@ -25,7 +30,9 @@ "description": "Advert not found.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/AdvertNotFound" } + "schema": { + "$ref": "#/components/schemas/AdvertNotFound" + } } } } @@ -38,59 +45,89 @@ "parameters": [ { "name": "search", + "description": "String to search for in adverts.", "required": false, "in": "query", - "description": "String to search for in adverts.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", + "description": "Page number to return.", "required": false, "in": "query", - "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } }, { "name": "department", + "description": "One or more departments (by `slug`) to filter on.", "required": false, "in": "query", - "description": "One or more departments (by `slug`) to filter on.", - "schema": { "type": "array", "items": { "type": "string" } } + "schema": { + "type": "array", + "items": { + "type": "string" + } + } }, { "name": "type", + "description": "One or more types (by `slug`) to filter on.", "required": false, "in": "query", - "description": "One or more types (by `slug`) to filter on.", - "schema": { "type": "array", "items": { "type": "string" } } + "schema": { + "type": "array", + "items": { + "type": "string" + } + } }, { "name": "category", + "description": "One or more categories (by `slug`) to filter on.", "required": false, "in": "query", - "description": "One or more categories (by `slug`) to filter on.", - "schema": { "type": "array", "items": { "type": "string" } } + "schema": { + "type": "array", + "items": { + "type": "string" + } + } }, { "name": "involvedParty", + "description": "One or more involved parties (by `slug`) to filter on.", "required": false, "in": "query", - "description": "One or more involved parties (by `slug`) to filter on.", - "schema": { "type": "array", "items": { "type": "string" } } + "schema": { + "type": "array", + "items": { + "type": "string" + } + } }, { "name": "dateFrom", + "description": "Date from which to filter adverts on, inclusive, takes into account `createdDate`, `updatedDate` and `signatureDate`.", "required": false, "in": "query", - "description": "Date from which to filter adverts on, inclusive, takes into account `createdDate`, `updatedDate` and `signatureDate`.", - "schema": { "format": "date-time", "type": "string" } + "schema": { + "format": "date-time", + "type": "string" + } }, { "name": "dateTo", + "description": "Date to which to filter adverts on, inclusive, takes into account `createdDate`, `updatedDate` and `signatureDate`.", "required": false, "in": "query", - "description": "Date to which to filter adverts on, inclusive, takes into account `createdDate`, `updatedDate` and `signatureDate`.", - "schema": { "format": "date-time", "type": "string" } + "schema": { + "format": "date-time", + "type": "string" + } } ], "responses": { @@ -98,7 +135,9 @@ "description": "List of adverts, optional query parameters.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/GetAdvertsResponse" } + "schema": { + "$ref": "#/components/schemas/GetAdvertsResponse" + } } } }, @@ -106,7 +145,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -122,14 +163,18 @@ "required": false, "in": "query", "description": "String to search for in departments.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } } ], "responses": { @@ -147,7 +192,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -163,21 +210,36 @@ "required": false, "in": "query", "description": "Department slug to get categories for.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "search", "required": false, "in": "query", "description": "String to search for in types.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } + }, + { + "name": "pageSize", + "required": false, + "in": "query", + "description": "Number of items per page.", + "schema": { + "type": "number" + } } ], "responses": { @@ -195,7 +257,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -211,14 +275,18 @@ "required": false, "in": "query", "description": "String to search for in main categories.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } } ], "responses": { @@ -236,7 +304,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -252,14 +322,18 @@ "required": false, "in": "query", "description": "String to search for in categories.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } } ], "responses": { @@ -277,7 +351,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -293,14 +369,18 @@ "required": false, "in": "query", "description": "String to search for in institutions.", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } } ], "responses": { @@ -318,7 +398,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -334,7 +416,9 @@ "required": false, "in": "query", "description": "Search for a specific signature by id", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "type", @@ -342,7 +426,9 @@ "in": "query", "description": "Search for a specific signature by type", "example": "Regular", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "search", @@ -350,14 +436,18 @@ "in": "query", "description": "Search for a specific signature", "example": "Dagur B. Eggertsson", - "schema": { "type": "string" } + "schema": { + "type": "string" + } }, { "name": "page", "required": false, "in": "query", "description": "Page number to return.", - "schema": { "type": "number" } + "schema": { + "type": "number" + } } ], "responses": { @@ -375,7 +465,9 @@ "description": "Query string validation failed.", "content": { "application/json": { - "schema": { "$ref": "#/components/schemas/ValidationResponse" } + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } } } } @@ -397,7 +489,11 @@ "get": { "operationId": "HealthController_health", "parameters": [], - "responses": { "200": { "description": "Health check endpoint." } } + "responses": { + "200": { + "description": "Health check endpoint." + } + } } } }, @@ -455,7 +551,11 @@ "department": { "description": "Department the advert type belongs to.", "nullable": true, - "allOf": [{ "$ref": "#/components/schemas/Department" }] + "allOf": [ + { + "$ref": "#/components/schemas/Department" + } + ] } }, "required": ["id", "title", "slug", "department"] @@ -531,7 +631,11 @@ "description": "The main category this category belongs to.", "nullable": true, "example": "Dómstólar og réttarfar", - "allOf": [{ "$ref": "#/components/schemas/MainCategory" }] + "allOf": [ + { + "$ref": "#/components/schemas/MainCategory" + } + ] } }, "required": ["id", "title", "slug"] @@ -635,7 +739,9 @@ "example": true, "nullable": false, "type": "array", - "items": { "$ref": "#/components/schemas/AdvertSignatureMember" } + "items": { + "$ref": "#/components/schemas/AdvertSignatureMember" + } } }, "required": ["institution", "date", "members"] @@ -670,7 +776,9 @@ "example": true, "nullable": false, "type": "array", - "items": { "$ref": "#/components/schemas/AdvertSignatureData" } + "items": { + "$ref": "#/components/schemas/AdvertSignatureData" + } } }, "required": ["id", "advertId", "type", "data"] @@ -709,12 +817,20 @@ "description": "The department the advert is for.", "nullable": false, "example": "A deild", - "allOf": [{ "$ref": "#/components/schemas/Department" }] + "allOf": [ + { + "$ref": "#/components/schemas/Department" + } + ] }, "type": { "description": "Type of the advert.", "example": "GJALDSKRÁ", - "allOf": [{ "$ref": "#/components/schemas/AdvertType" }] + "allOf": [ + { + "$ref": "#/components/schemas/AdvertType" + } + ] }, "subject": { "type": "string", @@ -748,7 +864,9 @@ "description": "Publication number of the advert", "nullable": true, "allOf": [ - { "$ref": "#/components/schemas/AdvertPublicationNumber" } + { + "$ref": "#/components/schemas/AdvertPublicationNumber" + } ] }, "createdDate": { @@ -779,26 +897,42 @@ "description": "List of advert categories.", "nullable": false, "type": "array", - "items": { "$ref": "#/components/schemas/Category" } + "items": { + "$ref": "#/components/schemas/Category" + } }, "involvedParty": { "description": "Involved party for the advert.", "nullable": false, - "allOf": [{ "$ref": "#/components/schemas/Institution" }] + "allOf": [ + { + "$ref": "#/components/schemas/Institution" + } + ] }, "document": { "description": "Advert document in different formats.", "nullable": false, - "allOf": [{ "$ref": "#/components/schemas/AdvertDocument" }] + "allOf": [ + { + "$ref": "#/components/schemas/AdvertDocument" + } + ] }, "signature": { "description": "Signatures for the advert.", - "allOf": [{ "$ref": "#/components/schemas/AdvertSignature" }] + "allOf": [ + { + "$ref": "#/components/schemas/AdvertSignature" + } + ] }, "attachments": { "description": "Attachments for the advert.", "type": "array", - "items": { "$ref": "#/components/schemas/AdvertAttachment" } + "items": { + "$ref": "#/components/schemas/AdvertAttachment" + } } }, "required": [ @@ -819,6 +953,20 @@ "attachments" ] }, + "GetAdvertResponse": { + "type": "object", + "properties": { + "advert": { + "description": "Advert", + "allOf": [ + { + "$ref": "#/components/schemas/Advert" + } + ] + } + }, + "required": ["advert"] + }, "AdvertNotFound": { "type": "object", "properties": { @@ -826,26 +974,52 @@ "type": "number", "description": "HTTP status code of response" }, - "message": { "type": "string", "description": "Response message" } + "message": { + "type": "string", + "description": "Response message" + } }, "required": ["statusCode", "message"] }, "Paging": { "type": "object", "properties": { - "page": { "type": "number", "example": 1 }, - "totalPages": { "type": "number", "example": 10 }, - "totalItems": { "type": "number", "example": 1000 }, - "nextPage": { "type": "number", "example": 2, "nullable": true }, - "previousPage": { "type": "number", "example": 1, "nullable": true }, + "page": { + "type": "number", + "example": 1 + }, + "totalPages": { + "type": "number", + "example": 10 + }, + "totalItems": { + "type": "number", + "example": 1000 + }, + "nextPage": { + "type": "number", + "example": 2, + "nullable": true + }, + "previousPage": { + "type": "number", + "example": 1, + "nullable": true + }, "pageSize": { "type": "number", "example": 10, "minimum": 1, "maximum": 100 }, - "hasNextPage": { "type": "boolean", "example": true }, - "hasPreviousPage": { "type": "boolean", "example": false } + "hasNextPage": { + "type": "boolean", + "example": true + }, + "hasPreviousPage": { + "type": "boolean", + "example": false + } }, "required": [ "page", @@ -864,11 +1038,17 @@ "adverts": { "description": "List of adverts", "type": "array", - "items": { "$ref": "#/components/schemas/Advert" } + "items": { + "$ref": "#/components/schemas/Advert" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["adverts", "paging"] @@ -882,7 +1062,9 @@ "message must be shorter than or equal to 10 characters" ], "type": "array", - "items": { "type": "string" } + "items": { + "type": "string" + } }, "error": { "type": "string", @@ -903,11 +1085,17 @@ "departments": { "description": "List of departments", "type": "array", - "items": { "$ref": "#/components/schemas/Department" } + "items": { + "$ref": "#/components/schemas/Department" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["departments", "paging"] @@ -918,11 +1106,17 @@ "types": { "description": "List of advert types", "type": "array", - "items": { "$ref": "#/components/schemas/AdvertType" } + "items": { + "$ref": "#/components/schemas/AdvertType" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["types", "paging"] @@ -933,11 +1127,17 @@ "mainCategories": { "description": "List of main categories", "type": "array", - "items": { "$ref": "#/components/schemas/MainCategory" } + "items": { + "$ref": "#/components/schemas/MainCategory" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["mainCategories", "paging"] @@ -948,11 +1148,17 @@ "categories": { "description": "List of advert categories", "type": "array", - "items": { "$ref": "#/components/schemas/Category" } + "items": { + "$ref": "#/components/schemas/Category" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["categories", "paging"] @@ -963,11 +1169,17 @@ "institutions": { "description": "List of involved parties", "type": "array", - "items": { "$ref": "#/components/schemas/Institution" } + "items": { + "$ref": "#/components/schemas/Institution" + } }, "paging": { "description": "Paging info", - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["institutions", "paging"] @@ -979,12 +1191,18 @@ "description": "List of signatures", "nullable": false, "type": "array", - "items": { "$ref": "#/components/schemas/AdvertSignature" } + "items": { + "$ref": "#/components/schemas/AdvertSignature" + } }, "paging": { "description": "Paging information", "nullable": false, - "allOf": [{ "$ref": "#/components/schemas/Paging" }] + "allOf": [ + { + "$ref": "#/components/schemas/Paging" + } + ] } }, "required": ["items", "paging"] From 3e36d8fd95fb52c1087c13d42ac12a698a51e410 Mon Sep 17 00:00:00 2001 From: Hedinn Eiriksson Date: Thu, 30 May 2024 00:42:13 +0200 Subject: [PATCH 09/82] refactor(island-ui): Action card (#14971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: remove secondaryCta and deleteButton * ActionCard redesign * layout when no cta and color themes * clean up * Render Heading * better default for text CTA * clean up * Fixes based on code rabbit review. * change string type * Move ProgressMeterVariant type to types.ts file to unblock api build. --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: Sævar Már Atlason --- .../core/src/lib/ActionCard/ActionCard.css.ts | 4 +- .../src/lib/ActionCard/ActionCard.stories.tsx | 208 ++++++++--- .../core/src/lib/ActionCard/ActionCard.tsx | 326 +++++++++--------- .../core/src/lib/ActionCard/types.ts | 27 +- libs/island-ui/core/src/lib/Button/Button.tsx | 11 +- .../src/lib/ProgressMeter/ProgressMeter.tsx | 4 +- .../core/src/lib/ProgressMeter/types.ts | 1 + .../core/src/lib/Tooltip/Tooltip.css.ts | 3 + .../src/components/impacts/ImpactList.tsx | 90 +++-- 9 files changed, 423 insertions(+), 251 deletions(-) create mode 100644 libs/island-ui/core/src/lib/ProgressMeter/types.ts diff --git a/libs/island-ui/core/src/lib/ActionCard/ActionCard.css.ts b/libs/island-ui/core/src/lib/ActionCard/ActionCard.css.ts index 59b40f596f9e..252bab695a72 100644 --- a/libs/island-ui/core/src/lib/ActionCard/ActionCard.css.ts +++ b/libs/island-ui/core/src/lib/ActionCard/ActionCard.css.ts @@ -10,6 +10,7 @@ export const tag = style({ }, }), }) + export const avatar = style({ display: 'none', ...themeUtils.responsiveStyle({ @@ -24,7 +25,8 @@ export const avatar = style({ export const button = style({ ...themeUtils.responsiveStyle({ sm: { - alignSelf: 'flex-end', + alignSelf: 'stretch', + alignItems: 'flex-end', }, }), }) diff --git a/libs/island-ui/core/src/lib/ActionCard/ActionCard.stories.tsx b/libs/island-ui/core/src/lib/ActionCard/ActionCard.stories.tsx index 251626ee7386..74b169d7b8ad 100644 --- a/libs/island-ui/core/src/lib/ActionCard/ActionCard.stories.tsx +++ b/libs/island-ui/core/src/lib/ActionCard/ActionCard.stories.tsx @@ -1,19 +1,110 @@ import React from 'react' import { ActionCard } from './ActionCard' +import type { Meta, StoryObj } from '@storybook/react' +import { withFigma } from '../../utils/withFigma' +import type { ActionCardProps } from './types' +import DialogPrompt from '../DialogPrompt/DialogPrompt' +import { Icon } from '../IconRC/Icon' +import { Tag } from '../Tag/Tag' +import { Box } from '../Box/Box' +import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden' -export default { +const config: Meta = { title: 'Cards/ActionCard', component: ActionCard, + parameters: withFigma('Action Card'), + argTypes: { + heading: { + description: 'Heading text', + control: { type: 'text' }, + }, + headingVariant: { + description: 'Heading element', + control: { type: 'radio' }, + options: ['h3', 'h4'], + }, + text: { + description: 'Text below the heading', + control: { type: 'text' }, + }, + date: { + description: 'Display date with an icon', + control: { type: 'text' }, + }, + eyebrow: { + description: 'Eyebrow text', + control: { type: 'text' }, + }, + avatar: { + description: 'Display avatar based on the heading', + control: { type: 'boolean' }, + }, + cta: { + description: + "The main call to action. If `fluid: false` then the button isn't full width on mobile.", + control: { type: 'object' }, + }, + unavailable: { + description: + 'Show unavailability message. Leave message empty to hide tooltip.', + control: { type: 'object' }, + }, + backgroundColor: { + description: 'Color theme of the card', + control: { type: 'radio' }, + options: ['white', 'blue', 'red'], + }, + tag: { + description: 'Tag to display on the card', + control: { type: 'object' }, + }, + progressMeter: { + description: 'Show progress meter', + control: { type: 'object' }, + }, + focused: { + description: 'Show focused state', + control: { type: 'boolean' }, + }, + }, } +export default config -export const Default = () => ( - -) +const Template = (args) => +export const Default: StoryObj = Template.bind({}) + +Default.args = { + heading: 'The main heading', + headingVariant: 'h3', + + text: 'This is the text', + + date: '17. júní 1944', + eyebrow: 'Eyebrow', + avatar: true, + cta: { + label: 'Click me', + variant: 'primary', + }, + unavailable: { + active: false, + label: 'Label shown instead of CTA', + message: 'The message shown in the optional tooltip', + }, + backgroundColor: undefined, + tag: { + label: 'Tag', + variant: 'blue', + outlined: true, + }, + progressMeter: { + currentProgress: 75, + maxProgress: 100, + withLabel: false, + }, + focused: false, +} export const SmallHeading = () => ( ( /> ) +export const WithLargerButton = () => ( + +) + export const Unavailable = () => ( ( /> ) -export const SecondaryCTA = () => ( - -) - export const WithTag = () => ( ) @@ -87,26 +177,6 @@ export const ApplicationCardInProgressVariant = () => ( cta={{ label: 'Open application', variant: 'ghost', - size: 'small', - icon: undefined, - }} - /> -) - -export const ApplicationCardCompletedVariant = () => ( - @@ -120,7 +190,6 @@ export const Avatar = () => ( cta={{ label: 'Skoða upplýsingar', variant: 'text', - size: 'small', }} /> ) @@ -141,3 +210,56 @@ export const Destructive = () => ( }} /> ) + +export const WithRenderTag = () => ( + ( + + {cld} + + Delete + + + + + } + onConfirm={() => console.log('Delete confirmed')} + buttonTextConfirm="Delete" + buttonTextCancel="Cancel" + /> + + ), + }} + date="17. júní 1944" + /> +) + +export const WithRenderHeading = () => ( + ( + + + {heading} + + )} + /> +) diff --git a/libs/island-ui/core/src/lib/ActionCard/ActionCard.tsx b/libs/island-ui/core/src/lib/ActionCard/ActionCard.tsx index 731f7eb458b4..cca83b057a70 100644 --- a/libs/island-ui/core/src/lib/ActionCard/ActionCard.tsx +++ b/libs/island-ui/core/src/lib/ActionCard/ActionCard.tsx @@ -7,19 +7,19 @@ import { Button } from '../Button/Button' import { Tag } from '../Tag/Tag' import { Text } from '../Text/Text' import { Tooltip } from '../Tooltip/Tooltip' -import { Inline } from '../Inline/Inline' import * as styles from './ActionCard.css' import { Hidden } from '../Hidden/Hidden' import { Icon } from '../IconRC/Icon' -import DialogPrompt from '../DialogPrompt/DialogPrompt' import { ProgressMeter } from '../ProgressMeter/ProgressMeter' -import { ActionCardProps } from './types' +import type { ActionCardProps, BackgroundColor } from './types' const defaultCta = { variant: 'primary', icon: 'arrowForward', onClick: () => null, + fluid: true, } as const + const defaultTag = { variant: 'blue', outlined: true, @@ -32,29 +32,46 @@ const defaultUnavailable = { message: '', } as const -const defaultDelete = { - visible: false, - onClick: () => null, - disabled: true, - icon: 'trash', - dialogTitle: '', - dialogDescription: '', - dialogConfirmLabel: '', - dialogCancelLabel: '', -} as const +const backgroundMap: Record = { + blue: 'blue100', + red: 'red100', + white: 'white', +} +const colorMap: Record = { + blue: 'blue600', + red: 'red600', + white: 'currentColor', +} + +const eyebrowMap: Record = { + blue: 'purple400', + red: 'purple400', + white: 'blue400', +} + +const borderMap: Record = { + blue: 'blue100', + red: 'red200', + white: 'blue200', +} + +const avatarMap: Record = { + blue: { circle: 'blue200', text: 'blue400' }, + red: { circle: 'red200', text: 'red600' }, + white: { circle: 'blue100', text: 'blue400' }, +} export const ActionCard: React.FC> = ({ date, heading, headingVariant = 'h3', + renderHeading, text, eyebrow, backgroundColor = 'white', cta: _cta, - secondaryCta, tag: _tag, unavailable: _unavailable, - deleteButton: _delete, avatar, focused = false, progressMeter, @@ -62,26 +79,23 @@ export const ActionCard: React.FC> = ({ const cta = { ...defaultCta, ..._cta } const tag = { ...defaultTag, ..._tag } const unavailable = { ...defaultUnavailable, ..._unavailable } - const deleteButton = { ...defaultDelete, ..._delete } - const backgroundMap: Record = { - blue: 'blue100', - red: 'red100', - white: 'white', - } - const colorMap: Record = { - blue: 'blue600', - red: 'red600', - white: 'currentColor', - } + const bgr = backgroundMap[backgroundColor] const color = colorMap[backgroundColor] + const eyebrowColor = eyebrowMap[backgroundColor] + const avatarColors = avatarMap[backgroundColor] + const borderColor = borderMap[backgroundColor] + + const hasEyebrowElements = Boolean(date || eyebrow) + const hasCTAElements = Boolean(cta?.label || unavailable?.active) + const hasTag = Boolean(tag?.label) const renderAvatar = () => { - if (!avatar) { + if (!avatar || !heading) { return null } - return heading ? ( + return ( > = ({ flexShrink={0} marginRight={[2, 3]} borderRadius="circle" - background="blue100" + background={avatarColors.circle} className={styles.avatar} > - + {getTitleAbbreviation(heading)} - ) : null + ) } const renderDisabled = () => { - const { label, message } = unavailable + if (!unavailable?.active) { + return null + } return ( - {label}  - + {unavailable.label}  + ) } @@ -121,17 +137,14 @@ export const ActionCard: React.FC> = ({ display="flex" flexDirection="row" justifyContent={eyebrow ? 'spaceBetween' : 'flexEnd'} - marginBottom={[0, 1]} > - + {eyebrow} - - {renderTag()} - {renderDelete()} ) } + const renderDate = () => { if (!date) { return null @@ -143,7 +156,6 @@ export const ActionCard: React.FC> = ({ display="flex" flexDirection="row" justifyContent={date ? 'spaceBetween' : 'flexEnd'} - marginBottom={[0, 2]} > > = ({ justifyContent="center" > - + {date} - - {!eyebrow && renderTag()} - {!eyebrow && renderDelete()} - ) } @@ -171,118 +184,125 @@ export const ActionCard: React.FC> = ({ return null } - return ( + const tagEl = ( {tag.label} ) + + return tag.renderTag ? tag.renderTag(tagEl) : tagEl } - const renderDelete = () => { - if (!deleteButton.visible) { + const renderCTA = () => { + if (!cta?.label || unavailable?.active) { return null } + const isTextVariant = + cta?.variant === 'text' || cta.buttonType?.variant === 'text' + + // varinat="text" buttons should be small + const smallButton = isTextVariant && _cta?.size === undefined + + // variant="text" buttons should not full width on mobile + const intrinsicSize = isTextVariant && _cta?.fluid === undefined + return ( - - } - disclosureElement={ - - - - - - } - onConfirm={deleteButton.onClick} - buttonTextConfirm={deleteButton.dialogConfirmLabel} - buttonTextCancel={deleteButton.dialogCancelLabel} - /> + + + ) } - const renderDefault = () => { - const hasCTA = !!cta.label - const hasSecondaryCTA = - hasCTA && secondaryCta?.label && secondaryCta?.visible + const renderProgressMeter = () => { + if (!progressMeter) { + return null + } return ( - hasCTA && ( - - {hasSecondaryCTA && ( - - - - )} - - - - - ) + + + ) } + const headingEl = ( + + {heading} + + ) + return ( - {renderEyebrow()} + {hasEyebrowElements ? ( + // The top box + + + {renderDate()} + {renderEyebrow()} + + + {renderTag()} + + ) : null} - {renderDate()} {renderAvatar()} + {heading && ( > = ({ justifyContent="spaceBetween" alignItems={['flexStart', 'flexStart', 'flexEnd']} > - - {heading} - - - {!date && !eyebrow && renderTag()} - + {renderHeading ? renderHeading(headingEl) : headingEl} + + {hasEyebrowElements ? null : ( + {renderTag()} + )} + + {!hasCTAElements && !hasEyebrowElements ? ( + {renderTag()} + ) : null} )} @@ -305,43 +328,30 @@ export const ActionCard: React.FC> = ({ {text} )} + + {renderProgressMeter()} + - {!date && !eyebrow && renderTag()} - {unavailable.active ? renderDisabled() : renderDefault()} + {hasEyebrowElements || !hasTag ? null : ( + + {renderTag()} + + )} + + {unavailable.active ? renderDisabled() : renderCTA()} - {progressMeter && ( - - - - )} ) } diff --git a/libs/island-ui/core/src/lib/ActionCard/types.ts b/libs/island-ui/core/src/lib/ActionCard/types.ts index 9c6e3a1aa09e..c75737c367e2 100644 --- a/libs/island-ui/core/src/lib/ActionCard/types.ts +++ b/libs/island-ui/core/src/lib/ActionCard/types.ts @@ -1,19 +1,24 @@ import type { ButtonSizes, ButtonTypes } from '../Button/types' import type { TagVariant } from '../Tag/types' import type { Icon as IconType } from '../IconRC/iconMap' +import type { ProgressMeterVariant } from '../ProgressMeter/types' + +export type BackgroundColor = 'white' | 'blue' | 'red' export type ActionCardProps = { date?: string heading?: string headingVariant?: 'h3' | 'h4' + renderHeading?: (headingEl: React.ReactNode) => React.ReactNode text?: string eyebrow?: string - backgroundColor?: 'white' | 'blue' | 'red' + backgroundColor?: BackgroundColor focused?: boolean tag?: { label: string variant?: TagVariant outlined?: boolean + renderTag?: (tagEl: React.ReactNode) => React.ReactNode } cta?: { label: string @@ -26,14 +31,7 @@ export type ActionCardProps = { iconType?: 'filled' | 'outline' onClick?: () => void disabled?: boolean - } - secondaryCta?: { - label: string - visible?: boolean - size?: ButtonSizes - icon?: IconType - onClick?: () => void - disabled?: boolean + fluid?: boolean } unavailable?: { active?: boolean @@ -41,19 +39,10 @@ export type ActionCardProps = { message?: string } avatar?: boolean - deleteButton?: { - visible?: boolean - onClick?: () => void - disabled?: boolean - icon?: IconType - dialogTitle?: string - dialogDescription?: string - dialogConfirmLabel?: string - dialogCancelLabel?: string - } progressMeter?: { currentProgress: number maxProgress: number withLabel?: boolean + variant?: ProgressMeterVariant } } diff --git a/libs/island-ui/core/src/lib/Button/Button.tsx b/libs/island-ui/core/src/lib/Button/Button.tsx index 8b3d4c1d3c45..18896eb7176b 100644 --- a/libs/island-ui/core/src/lib/Button/Button.tsx +++ b/libs/island-ui/core/src/lib/Button/Button.tsx @@ -5,8 +5,9 @@ import cn from 'classnames' import { Box } from '../Box/Box' import * as styles from './Button.css' import { Icon } from '../IconRC/Icon' +import type { IconProps } from '../IconRC/types' import { TestSupport } from '@island.is/island-ui/utils' -import { ButtonProps, ButtonTypes } from './types' +import type { ButtonProps, ButtonTypes } from './types' export type ButtonBaseProps = ButtonProps & ButtonTypes @@ -111,16 +112,16 @@ export const Button = forwardRef< ) type ButtonIconProps = { - icon: ButtonProps['icon'] - type: ButtonProps['iconType'] + icon: IconProps['icon'] + type: IconProps['type'] transparent?: boolean preText?: boolean } const ButtonIcon = ({ icon, type, transparent, preText }: ButtonIconProps) => ( { : impactMsgs.typeCancellation, ), variant: isChange ? 'blueberry' : 'red', + renderTag: (child) => ( + + {child} + + {idx === impactGroup.length - 1 ? ( + + } + disclosureElement={ + + + {formatMessage( + impactMsgs.impactListDeleteButton, + )} + + + + + + + } + onConfirm={() => { + deleteImpact(impact) + setTimeout(() => { + document.location.reload() + }, 250) + }} + buttonTextConfirm={formatMessage( + impactMsgs.impactListDeleteButton, + )} + buttonTextCancel={formatMessage( + impactMsgs.cancelButton, + )} + /> + ) : null} + + ), }} cta={{ icon: undefined, @@ -161,29 +228,6 @@ export const ImpactList = (props: ImpactListProps) => { }) }, }} - deleteButton={{ - icon: 'trash', - visible: idx === impactGroup.length - 1, - dialogTitle: formatMessage( - impactMsgs.impactListDeleteButton, - ), - dialogDescription: formatMessage( - impactMsgs.deleteConfirmation, - ), - dialogConfirmLabel: formatMessage( - impactMsgs.impactListDeleteButton, - ), - dialogCancelLabel: formatMessage( - impactMsgs.cancelButton, - ), - disabled: idx !== impactGroup.length - 1, - onClick: () => { - deleteImpact(impact) - setTimeout(() => { - document.location.reload() - }, 250) - }, - }} text={ errorMessage && (( From 5308bffc6dbabd61c9a59ff621818bd23acb2d9f Mon Sep 17 00:00:00 2001 From: berglindoma13 Date: Thu, 30 May 2024 08:54:40 +0000 Subject: [PATCH 10/82] fix(citizenship): citizenship for children fix (#15006) * small citizenship update * space --- .../src/lib/directorateOfImmigrationClient.service.ts | 5 ++++- .../src/lib/directorateOfImmigrationClient.types.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.service.ts b/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.service.ts index 316482249036..12eedcfc42ab 100644 --- a/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.service.ts +++ b/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.service.ts @@ -270,6 +270,9 @@ export class DirectorateOfImmigrationClient { const childInfo = application.children.find( (c) => c.nationalId === childNationalId, ) + const childCitizenship = application.selectedChildren.find( + (x) => x.nationalId === childNationalId, + )?.citizenship if (!childInfo) { continue @@ -310,7 +313,7 @@ export class DirectorateOfImmigrationClient { ? new Date(selectedChild.otherParentBirtDate).toISOString() : undefined, parent2Name: selectedChild.otherParentName, - nationality: childInfo.citizenship, + nationality: childCitizenship, }, }, }) diff --git a/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.types.ts b/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.types.ts index dc528da47edc..e8a18283ee41 100644 --- a/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.types.ts +++ b/libs/clients/directorate-of-immigration/src/lib/directorateOfImmigrationClient.types.ts @@ -4,6 +4,7 @@ export interface CitizenshipApplication { otherParentNationalId?: string otherParentBirtDate?: Date otherParentName?: string + citizenship?: string }[] isFormerIcelandicCitizen: boolean givenName?: string | null @@ -68,7 +69,6 @@ export interface CitizenshipApplication { fullName: string givenName?: string | null familyName?: string | null - citizenship?: string }[] childrenPassport: { nationalId: string From f67099f5b21557987f0b25e426ea48d108504ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9tur=20Neisti=20Erlingsson?= Date: Thu, 30 May 2024 09:51:53 +0000 Subject: [PATCH 11/82] Revert "fix: init dd-trace with node (#14972)" (#15009) This reverts commit cf2f7ea141299c7ea2d3dc2760aadd0f28141bf4. --- charts/identity-server/values.dev.yaml | 18 ++--- charts/identity-server/values.prod.yaml | 18 ++--- charts/identity-server/values.staging.yaml | 18 ++--- charts/islandis/values.dev.yaml | 72 +++++++++---------- charts/islandis/values.prod.yaml | 68 +++++++++--------- charts/islandis/values.staging.yaml | 64 ++++++++--------- charts/judicial-system/values.dev.yaml | 16 ++--- charts/judicial-system/values.prod.yaml | 16 ++--- charts/judicial-system/values.staging.yaml | 16 ++--- infra/src/dsl/basic.spec.ts | 2 +- infra/src/dsl/feature-values.spec.ts | 2 +- .../output-generators/map-to-helm-values.ts | 2 +- infra/src/dsl/postgres.spec.ts | 2 +- 13 files changed, 157 insertions(+), 157 deletions(-) diff --git a/charts/identity-server/values.dev.yaml b/charts/identity-server/values.dev.yaml index 9f9bb6685b83..11448bc333ac 100644 --- a/charts/identity-server/values.dev.yaml +++ b/charts/identity-server/values.dev.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.dev01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.dev01.devland.is","https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' NOVA_ACCEPT_UNAUTHORIZED: 'true' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -627,7 +627,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -698,7 +698,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/identity-server/values.prod.yaml b/charts/identity-server/values.prod.yaml index 7c68d1aa4457..f1eb83b1f8da 100644 --- a/charts/identity-server/values.prod.yaml +++ b/charts/identity-server/values.prod.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://innskra.island.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -112,7 +112,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'https://service-portal-api.internal.island.is' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'true' PersistenceSettings__SessionsBaseAddress: 'https://sessions-api.internal.island.is' @@ -217,7 +217,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -285,7 +285,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' USER_NOTIFICATION_API_URL: 'https://user-notification.internal.island.is' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -372,7 +372,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -487,7 +487,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -542,7 +542,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -616,7 +616,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -687,7 +687,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/identity-server/values.staging.yaml b/charts/identity-server/values.staging.yaml index fa80d892debd..c495716079b6 100644 --- a/charts/identity-server/values.staging.yaml +++ b/charts/identity-server/values.staging.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.staging01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -619,7 +619,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -690,7 +690,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index 0d5633e3742d..f9e8ac904fef 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.dev01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -599,7 +599,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'true' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -814,7 +814,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -899,7 +899,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_PATH: '' @@ -972,7 +972,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.dev01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1033,7 +1033,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1097,7 +1097,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1165,7 +1165,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1280,7 +1280,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1371,7 +1371,7 @@ external-contracts-tests: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1433,7 +1433,7 @@ github-actions-cache: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_NODES: 'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] @@ -1514,7 +1514,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1599,7 +1599,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -1660,7 +1660,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1778,7 +1778,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' @@ -1847,7 +1847,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1943,7 +1943,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=3686' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -2068,7 +2068,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2150,7 +2150,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2277,7 +2277,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2353,7 +2353,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2431,7 +2431,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2502,7 +2502,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2565,7 +2565,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2659,7 +2659,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2788,7 +2788,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2863,7 +2863,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2933,7 +2933,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -3043,7 +3043,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3134,7 +3134,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -3238,7 +3238,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3336,7 +3336,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.dev01.devland.is' grantNamespaces: @@ -3408,7 +3408,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 7feb51773a83..600f523374fd 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -90,7 +90,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -194,7 +194,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.island.is' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -303,7 +303,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'island@island.is' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -589,7 +589,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'island@island.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Stafrænt Ísland' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Production' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -804,7 +804,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -889,7 +889,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_PATH: '' @@ -965,7 +965,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://island.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1029,7 +1029,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1092,7 +1092,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1160,7 +1160,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS/EDU/4112043590/LBHI-Protected/brautskraning-v1' @@ -1275,7 +1275,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1382,7 +1382,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -1467,7 +1467,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -1527,7 +1527,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1643,7 +1643,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' @@ -1715,7 +1715,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1811,7 +1811,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=3686' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1936,7 +1936,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2021,7 +2021,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2148,7 +2148,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2224,7 +2224,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -2302,7 +2302,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2373,7 +2373,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -2436,7 +2436,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2530,7 +2530,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2659,7 +2659,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2734,7 +2734,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -2807,7 +2807,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'application-system' @@ -2920,7 +2920,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3011,7 +3011,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -3115,7 +3115,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3213,7 +3213,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TRACKING_DOMAIN: 'island.is' grantNamespaces: @@ -3289,7 +3289,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index e5900abff5fd..a9f2d39d7529 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.staging01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=1843' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -597,7 +597,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -812,7 +812,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -897,7 +897,7 @@ application-system-form: env: BASEPATH: '/umsoknir' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_PATH: '' @@ -971,7 +971,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.staging01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1035,7 +1035,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1151,7 +1151,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1258,7 +1258,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1343,7 +1343,7 @@ island-ui-storybook: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -1404,7 +1404,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1519,7 +1519,7 @@ portals-admin: env: BASEPATH: '/stjornbord' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' @@ -1589,7 +1589,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1685,7 +1685,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=3686' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1810,7 +1810,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -1893,7 +1893,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2020,7 +2020,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2096,7 +2096,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2174,7 +2174,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2245,7 +2245,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2308,7 +2308,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2402,7 +2402,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2531,7 +2531,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2606,7 +2606,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2676,7 +2676,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -2786,7 +2786,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -2877,7 +2877,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2981,7 +2981,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=345' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3080,7 +3080,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=691' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.staging01.devland.is' grantNamespaces: @@ -3152,7 +3152,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index 8d670725811a..c20aacc92019 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'true' S3_BUCKET: 'island-is-dev-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.dev01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index 2e9c2f0aadc8..3a9c94c20cd8 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://ws.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-prod-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://rettarvorslugatt.island.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index 3cb6162b7289..f93fd2f7c445 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=460' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=921' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-staging-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.staging01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/infra/src/dsl/basic.spec.ts b/infra/src/dsl/basic.spec.ts index f3d24bb8d736..e4201e50236e 100644 --- a/infra/src/dsl/basic.spec.ts +++ b/infra/src/dsl/basic.spec.ts @@ -103,7 +103,7 @@ describe('Basic serialization', () => { DB_NAME: 'api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init', + NODE_OPTIONS: '--max-old-space-size=460', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) diff --git a/infra/src/dsl/feature-values.spec.ts b/infra/src/dsl/feature-values.spec.ts index 9ee13cb2f03d..eba9a6d3cf28 100644 --- a/infra/src/dsl/feature-values.spec.ts +++ b/infra/src/dsl/feature-values.spec.ts @@ -94,7 +94,7 @@ describe('Feature-deployment support', () => { DB_NAME: 'feature_feature_A_graphql', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', + NODE_OPTIONS: '--max-old-space-size=230', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', DB_EXTENSIONS: 'foo', diff --git a/infra/src/dsl/output-generators/map-to-helm-values.ts b/infra/src/dsl/output-generators/map-to-helm-values.ts index 786140c04abf..7bead10451ff 100644 --- a/infra/src/dsl/output-generators/map-to-helm-values.ts +++ b/infra/src/dsl/output-generators/map-to-helm-values.ts @@ -60,7 +60,7 @@ const serializeService: SerializeMethod = async ( SERVERSIDE_FEATURES_ON: env1.featuresOn.join(','), NODE_OPTIONS: `--max-old-space-size=${getScaledValue( serviceDef.resources.limits.memory, - )} -r dd-trace/init`, + )}`, LOG_LEVEL: 'info', }, secrets: {}, diff --git a/infra/src/dsl/postgres.spec.ts b/infra/src/dsl/postgres.spec.ts index 7c7e73c68652..ddb7d0753888 100644 --- a/infra/src/dsl/postgres.spec.ts +++ b/infra/src/dsl/postgres.spec.ts @@ -41,7 +41,7 @@ describe('Postgres', () => { DB_NAME: 'service_portal_api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', + NODE_OPTIONS: '--max-old-space-size=230', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) From cd01b3013fc3619899b5e84eb012dc0c7c620d2c Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Thu, 30 May 2024 10:03:31 +0000 Subject: [PATCH 12/82] fix(inheritance-report): EFS after discussion 23/5 (#14916) * readonly for initial fields * exchangeRateOrInterest currency * debts overview * minor tweaks * form tweak * lint fix * project cleanup * tweaks * ui and error tweaks * fix for suffix in assets repeater * chore: nx format:write update dirty files * tweaks * bug fixes * custom share * tweaks * customShare options --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../inheritance-report/utils/mappers.ts | 2 +- .../src/fields/AssetsRepeater/index.tsx | 2 - .../src/fields/OtherAssetsRepeater/index.tsx | 2 + .../src/assets/Grieving.tsx | 3959 ----------------- .../src/components/DeceasedShare/index.tsx | 7 +- .../src/components/ShareInput/index.tsx | 9 +- .../src/dataProviders/EstateProvider.ts | 5 - .../src/dataProviders/index.ts | 7 +- .../src/fields/AssetsRepeater/index.tsx | 20 +- .../src/fields/CalculateShare/index.tsx | 21 +- .../src/fields/Cards/index.tsx | 67 - .../src/fields/DoneImage/index.tsx | 12 - .../AdditionalHeir.tsx | 13 +- .../HeirsAndPartitionRepeater/index.tsx | 6 +- .../src/fields/NotFilledOut/index.tsx | 14 - .../src/fields/OtherAssetsRepeater/index.tsx | 4 +- .../{ => Overview}/OverviewAssets/index.tsx | 4 +- .../{ => Overview}/OverviewAssets/rows.ts | 17 +- .../{ => Overview}/OverviewAssets/types.ts | 0 .../fields/Overview/OverviewDebts/index.tsx | 185 + .../src/fields/ReportFieldsRepeater/index.tsx | 27 +- .../inheritance-report/src/fields/index.ts | 5 +- .../src/fields/styles.css.ts | 12 - .../forms/OverviewSections/OverviewAssets.ts | 507 --- .../inheritance-report/src/forms/done.ts | 25 +- .../src/forms/sections/applicant.ts | 3 + .../src/forms/sections/assets.ts | 30 +- .../src/forms/sections/dataCollection.ts | 15 +- .../src/forms/sections/debtsAndFuneralCost.ts | 270 +- .../src/forms/sections/deceased.ts | 32 + .../src/forms/sections/heirs.ts | 65 +- .../inheritance-report/src/lib/dataSchema.ts | 19 +- .../inheritance-report/src/lib/messages.ts | 59 +- .../templates/inheritance-report/src/types.ts | 1 + .../inheritance-report/src/types/index.ts | 28 - 35 files changed, 426 insertions(+), 5028 deletions(-) delete mode 100644 libs/application/templates/inheritance-report/src/assets/Grieving.tsx delete mode 100644 libs/application/templates/inheritance-report/src/dataProviders/EstateProvider.ts delete mode 100644 libs/application/templates/inheritance-report/src/fields/Cards/index.tsx delete mode 100644 libs/application/templates/inheritance-report/src/fields/DoneImage/index.tsx delete mode 100644 libs/application/templates/inheritance-report/src/fields/NotFilledOut/index.tsx rename libs/application/templates/inheritance-report/src/fields/{ => Overview}/OverviewAssets/index.tsx (98%) rename libs/application/templates/inheritance-report/src/fields/{ => Overview}/OverviewAssets/rows.ts (95%) rename libs/application/templates/inheritance-report/src/fields/{ => Overview}/OverviewAssets/types.ts (100%) create mode 100644 libs/application/templates/inheritance-report/src/fields/Overview/OverviewDebts/index.tsx delete mode 100644 libs/application/templates/inheritance-report/src/forms/OverviewSections/OverviewAssets.ts delete mode 100644 libs/application/templates/inheritance-report/src/types/index.ts diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts index 60a03ade6192..4a154e52cb6b 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts @@ -287,7 +287,7 @@ export const expandAnswers = ( netPropertyForExchange: answers.netPropertyForExchange ?? 0, customShare: { hasCustomSpouseSharePercentage: - answers?.customShare?.hasCustomSpouseSharePercentage ?? [], + answers?.customShare?.hasCustomSpouseSharePercentage ?? 'No', customSpouseSharePercentage: answers?.customShare?.customSpouseSharePercentage ?? '50', }, diff --git a/libs/application/templates/estate/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/estate/src/fields/AssetsRepeater/index.tsx index 800774f56726..8d488cb6d832 100644 --- a/libs/application/templates/estate/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/estate/src/fields/AssetsRepeater/index.tsx @@ -13,8 +13,6 @@ import { } from '@island.is/island-ui/core' import { AssetFormField } from '../../types' -import { EstateAsset } from '@island.is/clients/syslumenn' - import * as styles from '../styles.css' import { m } from '../../lib/messages' import { getEstateDataFromApplication } from '../../lib/utils' diff --git a/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx b/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx index 3a07e9d7795e..3b6eb54731da 100644 --- a/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx +++ b/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx @@ -31,6 +31,8 @@ export const OtherAssetsRepeater: FC< name: id, }) + console.log(fields) + const { getValues } = useFormContext() const { formatMessage } = useLocale() diff --git a/libs/application/templates/inheritance-report/src/assets/Grieving.tsx b/libs/application/templates/inheritance-report/src/assets/Grieving.tsx deleted file mode 100644 index fb8c4802a1ac..000000000000 --- a/libs/application/templates/inheritance-report/src/assets/Grieving.tsx +++ /dev/null @@ -1,3959 +0,0 @@ -import React from 'react' - -const Grieving: React.FC> = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) - -export default Grieving diff --git a/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx b/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx index d70ac4135643..008ff942226a 100644 --- a/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx @@ -49,7 +49,7 @@ export const DeceasedShare = ({ const watchedCheckboxField = watch(checkboxFieldName) const watchedInputField = watch(inputFieldName) - const hasError = getErrorViaPath(errors, `${id}.${valueFieldName}`) + const error = getErrorViaPath(errors, `${id}.${valueFieldName}`) const checked = watchedCheckboxField?.[0] === YES useEffect(() => { @@ -67,7 +67,7 @@ export const DeceasedShare = ({ paddingBottom={paddingBottom} > - + diff --git a/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx b/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx index 3d8dda9ecc61..ec401e70e580 100644 --- a/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx +++ b/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx @@ -13,6 +13,8 @@ interface ShareInputProps { onAfterChange?: (value: number) => void disabled?: boolean required?: boolean + readOnly?: boolean + hasError?: boolean } const onFocusInput = ( @@ -53,6 +55,8 @@ export const ShareInput = ({ onAfterChange, disabled, required, + readOnly, + hasError, }: ShareInputProps) => { const ref = useRef(null) const prevLen = useRef(0) @@ -154,10 +158,11 @@ export const ShareInput = ({ return onAfterChange?.(numberValue) } }} - hasError={!!shareError} - errorMessage={shareError} + hasError={hasError ?? false} + errorMessage={formatMessage(m.invalidShareValue)} disabled={disabled} required={required} + readOnly={readOnly} /> )} /> diff --git a/libs/application/templates/inheritance-report/src/dataProviders/EstateProvider.ts b/libs/application/templates/inheritance-report/src/dataProviders/EstateProvider.ts deleted file mode 100644 index 40c41b65ba1e..000000000000 --- a/libs/application/templates/inheritance-report/src/dataProviders/EstateProvider.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineTemplateApi } from '@island.is/application/types' -export const EstateOnEntryApi = defineTemplateApi({ - action: 'syslumennOnEntry', - shouldPersistToExternalData: true, -}) diff --git a/libs/application/templates/inheritance-report/src/dataProviders/index.ts b/libs/application/templates/inheritance-report/src/dataProviders/index.ts index a3b10800405d..2be81a9dd001 100644 --- a/libs/application/templates/inheritance-report/src/dataProviders/index.ts +++ b/libs/application/templates/inheritance-report/src/dataProviders/index.ts @@ -1 +1,6 @@ -export { EstateOnEntryApi } from './EstateProvider' +import { defineTemplateApi } from '@island.is/application/types' + +export const EstateOnEntryApi = defineTemplateApi({ + action: 'syslumennOnEntry', + shouldPersistToExternalData: true, +}) diff --git a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx index f075d9dd8224..0ca425e5eba4 100644 --- a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx @@ -43,7 +43,6 @@ type RepeaterProps = { fields: Array repeaterButtonText: string sumField: string - fromExternalData?: string calcWithShareValue?: boolean assetKey?: string } @@ -113,7 +112,7 @@ export const AssetsRepeater: FC< acc[elem] = '' if (elem === 'share') { - acc[elem] = '100' + acc[elem] = '0' } return acc @@ -140,6 +139,7 @@ export const AssetsRepeater: FC< extData.map((x) => ({ ...x, share: String(x.share), + initial: true, })), ) setValue(`assets.${assetKey}.hasModified`, true) @@ -193,6 +193,7 @@ export const AssetsRepeater: FC< field={field} fieldName={fieldName} error={error} + readOnly={repeaterField.initial} /> ) })} @@ -253,6 +254,7 @@ interface FieldComponentProps { fieldIndex: string fieldName: string error?: string + readOnly?: boolean } const FieldComponent = ({ @@ -265,6 +267,7 @@ const FieldComponent = ({ fieldIndex, fieldName, error, + readOnly, }: FieldComponentProps) => { const { formatMessage } = useLocale() @@ -280,12 +283,12 @@ const FieldComponent = ({ placeholder: field.placeholder, backgroundColor: field.color ? field.color : 'blue', currency: field.currency, - readOnly: field.readOnly, required: field.required, loading: fieldName === loadingFieldName, - suffix: '', + suffix: field.suffix, onChange: () => onAfterChange?.(), error: error, + readOnly: readOnly, ...field, } @@ -303,6 +306,7 @@ const FieldComponent = ({ ) + case 'assetNumber': if (assetKey === 'assets') { content = ( @@ -325,18 +329,20 @@ const FieldComponent = ({ /> ) } - break + case 'share': content = ( ) - break + default: content = @@ -506,7 +512,7 @@ const VehicleNumberField = ({ name={fieldName} label={formatMessage(m.propertyNumber)} defaultValue={assetNumberInput} - error={error ? formatMessage(m.errorPropertyNumber) : undefined} + error={error} {...props} /> ) diff --git a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx index 39a5ef0e8978..a44921a647df 100644 --- a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx @@ -21,7 +21,6 @@ import { EstateAssets } from '../../types' import { MessageDescriptor } from 'react-intl' import { useFormContext } from 'react-hook-form' import { YES } from '../../lib/constants' -import ShareInput from '../../components/ShareInput' type CalcShared = { value: number @@ -65,7 +64,7 @@ export const CalculateShare: FC> = ({ const hasCustomSpouseSharePercentage = deceasedWasInCohabitation && - !!formValues?.customShare?.hasCustomSpouseSharePercentage?.includes(YES) + formValues?.customShare?.hasCustomSpouseSharePercentage === YES const [shareValues, setShareValues] = useState< Record, ShareItem> @@ -454,23 +453,7 @@ export const CalculateShare: FC> = ({ return ( - {hasCustomSpouseSharePercentage && ( - - - { - setCustomSpouseSharePercentage(val / 100) - }} - errorMessage={inputError} - required - /> - - - )} - - + { - title?: string - titleRequired?: boolean - description?: - | string - | string[] - | ((formatMessage: FormatMessage) => string | string[]) - }[] - } - } -} - -export const Cards: FC> = ({ - application, - field, -}) => { - const { formatMessage } = useLocale() - return ( - - {field.props.cards(application).length ? ( - field.props - .cards(application) - .map(({ title, description, titleRequired = true }, idx) => { - return ( - - {!titleRequired || (title && title !== '') ? ( - - - - ) : ( - - )} - - ) - }) - ) : ( - - - - )} - - ) -} - -export default Cards diff --git a/libs/application/templates/inheritance-report/src/fields/DoneImage/index.tsx b/libs/application/templates/inheritance-report/src/fields/DoneImage/index.tsx deleted file mode 100644 index c41bb96169d0..000000000000 --- a/libs/application/templates/inheritance-report/src/fields/DoneImage/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Box } from '@island.is/island-ui/core' -import Grieving from '../../assets/Grieving' - -export const DoneImage = () => { - return ( - - - - ) -} - -export default DoneImage diff --git a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx index 051a639bc682..80a77d2be928 100644 --- a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx +++ b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx @@ -58,7 +58,7 @@ export const AdditionalHeir = ({ const advocateField = `${fieldIndex}.advocate` const advocatePhoneField = `${advocateField}.phone` - const advocateEmailFeild = `${advocateField}.email` + const advocateEmailField = `${advocateField}.email` const foreignCitizenship = useWatch({ name: `${fieldIndex}.foreignCitizenship`, @@ -98,7 +98,7 @@ export const AdditionalHeir = ({ clearErrors(relationField) clearErrors(dateOfBirthField) clearErrors(advocatePhoneField) - clearErrors(advocateEmailFeild) + clearErrors(advocateEmailField) clearErrors(`${fieldIndex}.nationalId`) if (!requiresAdvocate) { @@ -278,6 +278,11 @@ export const AdditionalHeir = ({ ? error[index][customField.id] : undefined } + hasError={ + error && error[index] + ? !!error[index][customField.id] + : false + } required /> @@ -345,8 +350,8 @@ export const AdditionalHeir = ({ append({ @@ -442,6 +441,11 @@ export const HeirsAndPartitionRepeater: FC< onAfterChange={(val) => { updateValues(fieldIndex, val, customFieldIndex) }} + hasError={ + error && error[mainIndex] + ? !!error[mainIndex][customField.id] + : false + } errorMessage={ error && error[mainIndex] ? error[mainIndex][customField.id] diff --git a/libs/application/templates/inheritance-report/src/fields/NotFilledOut/index.tsx b/libs/application/templates/inheritance-report/src/fields/NotFilledOut/index.tsx deleted file mode 100644 index 44e3b52f53ce..000000000000 --- a/libs/application/templates/inheritance-report/src/fields/NotFilledOut/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useLocale } from '@island.is/localization' -import { m } from '../../lib/messages' -import { Box } from '@island.is/island-ui/core' - -export const NotFilledOut = () => { - const { formatMessage } = useLocale() - return ( - -

{formatMessage(m.notFilledOut)}

-
- ) -} - -export default NotFilledOut diff --git a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx index 964c41abd499..b2fa6cc0122d 100644 --- a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx @@ -12,7 +12,7 @@ import { useLocale } from '@island.is/localization' import { m } from '../../lib/messages' import DoubleColumnRow from '../../components/DoubleColumnRow' import { - getDeceasedHadAssets, + getDeceasedWasMarriedAndHadAssets, getEstateDataFromApplication, valueToNumber, } from '../../lib/utils/helpers' @@ -33,7 +33,7 @@ export const OtherAssetsRepeater: FC< > = ({ application, field, errors }) => { const { id, props } = field - const deceasedHadAssets = getDeceasedHadAssets(application) + const deceasedHadAssets = getDeceasedWasMarriedAndHadAssets(application) const getDefaultValue = ( fieldName: keyof InheritanceReportAsset, diff --git a/libs/application/templates/inheritance-report/src/fields/OverviewAssets/index.tsx b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx similarity index 98% rename from libs/application/templates/inheritance-report/src/fields/OverviewAssets/index.tsx rename to libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx index e60eed302acc..eb45507e36e6 100644 --- a/libs/application/templates/inheritance-report/src/fields/OverviewAssets/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx @@ -8,7 +8,7 @@ import { } from '@island.is/island-ui/core' import { useLocale } from '@island.is/localization' import { FC, Fragment } from 'react' -import { m } from '../../lib/messages' +import { m } from '../../../lib/messages' import { getBankAccountsDataRow, getClaimsDataRow, @@ -23,7 +23,7 @@ import { import { SectionType, RowProps, RowItemType } from './types' import { getValueViaPath } from '@island.is/application/core' import { formatCurrency } from '@island.is/application/ui-components' -import { calculateTotalAssets } from '../../lib/utils/calculateTotalAssets' +import { calculateTotalAssets } from '../../../lib/utils/calculateTotalAssets' export const OverviewAssets: FC> = ({ application, diff --git a/libs/application/templates/inheritance-report/src/fields/OverviewAssets/rows.ts b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts similarity index 95% rename from libs/application/templates/inheritance-report/src/fields/OverviewAssets/rows.ts rename to libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts index c6bd60bc60f5..c18ca63615be 100644 --- a/libs/application/templates/inheritance-report/src/fields/OverviewAssets/rows.ts +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts @@ -3,14 +3,15 @@ import { formatBankInfo, formatCurrency, } from '@island.is/application/ui-components' -import { m } from '../../lib/messages' +import { m } from '../../../lib/messages' import { roundedValueToNumber, valueToNumber, hasYes, -} from '../../lib/utils/helpers' -import { EstateAssets } from '../../types' +} from '../../../lib/utils/helpers' +import { EstateAssets } from '../../../types' import { RowType, RowItemsType } from './types' +import { format as formatNationalId } from 'kennitala' export const getRealEstateDataRow = (answers: FormValue): RowType[] => { const values = (answers.assets as unknown as EstateAssets)?.realEstate?.data @@ -181,7 +182,7 @@ export const getStocksDataRow = (answers: FormValue): RowType[] => { const items: RowItemsType = [ { title: m.nationalId, - value: item.nationalId ?? '-', + value: formatNationalId(item.assetNumber ?? '-'), }, { title: m.stocksFaceValue, @@ -253,10 +254,14 @@ export const getBankAccountsDataRow = (answers: FormValue): RowType[] => { export const getOtherAssetsDataRow = (answers: FormValue): RowType[] => { const values = (answers.assets as unknown as EstateAssets)?.otherAssets?.data - const items: RowItemsType = [] - const data = (values ?? []).map((item) => { const value = roundedValueToNumber(item.value) + const items: RowItemsType = [ + { + title: item.info, + value: formatCurrency(String(value)), + }, + ] const deceasedShare = valueToNumber(item.deceasedShare) diff --git a/libs/application/templates/inheritance-report/src/fields/OverviewAssets/types.ts b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/types.ts similarity index 100% rename from libs/application/templates/inheritance-report/src/fields/OverviewAssets/types.ts rename to libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/types.ts diff --git a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewDebts/index.tsx b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewDebts/index.tsx new file mode 100644 index 000000000000..e47625ef6187 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewDebts/index.tsx @@ -0,0 +1,185 @@ +import { FieldBaseProps } from '@island.is/application/types' +import { + Box, + Divider, + GridColumn, + GridRow, + Text, +} from '@island.is/island-ui/core' +import { useLocale } from '@island.is/localization' +import { FC } from 'react' +import { m } from '../../../lib/messages' +import { RowItemType } from '../OverviewAssets/types' +import { getValueViaPath } from '@island.is/application/core' +import { formatCurrency } from '@island.is/application/ui-components' +import { ApplicationDebts, Debt as DebtType } from '../../../types' +import { format as formatNationalId } from 'kennitala' + +export const OverviewDebts: FC> = ({ + application, +}) => { + const { formatMessage } = useLocale() + const { answers } = application + const debtsData = (answers.debts as unknown as ApplicationDebts) + ?.domesticAndForeignDebts.data + + return ( + + {debtsData && debtsData.length ? ( + debtsData.map((debt: DebtType, index: number) => ( + + )) + ) : ( + + )} + + (answers, 'funeralCost.total') || '0'} + /> + + + (answers, 'funeralCost.build') || '0', + )} + /> + (answers, 'funeralCost.cremation') || '0', + )} + /> + (answers, 'funeralCost.print') || '0', + )} + /> + (answers, 'funeralCost.flowers') || '0', + )} + /> + (answers, 'funeralCost.music') || '0', + )} + /> + (answers, 'funeralCost.rent') || '0', + )} + /> + (answers, 'funeralCost.food') || '0', + )} + /> + (answers, 'funeralCost.tombstone') || '0', + )} + /> + (answers, 'funeralCost.other') || '0', + )} + /> + + + + + + + ) +} + +export default OverviewDebts + +const Debt = ({ + assetNumber, + debtType, + description, + nationalId, + propertyValuation, +}: DebtType) => { + const { formatMessage } = useLocale() + + return ( + + {description && ( + + )} + + + + + + + ) +} + +const TopRow = ({ + title, + titleVariant = 'h4', + valueVariant = 'default', + value, +}: RowItemType) => { + const { formatMessage } = useLocale() + + return ( + + + + {typeof title === 'string' ? title : formatMessage(title)} + + + + + + {formatCurrency(value)} + + + + + ) +} + +const Row = ({ title, value }: RowItemType) => { + const { formatMessage } = useLocale() + + return ( + + + + {typeof title === 'string' ? title : formatMessage(title)} + + + + + + {value} + + + + + ) +} diff --git a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx index e7386e472552..a332fe271c74 100644 --- a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx @@ -24,7 +24,7 @@ import { m } from '../../lib/messages' import { YES } from '../../lib/constants' import DoubleColumnRow from '../../components/DoubleColumnRow' import { - getDeceasedHadAssets, + getDeceasedWasMarriedAndHadAssets, getEstateDataFromApplication, } from '../../lib/utils/helpers' import { @@ -32,7 +32,6 @@ import { InheritanceReportInfo, } from '@island.is/clients/syslumenn' import { valueToNumber } from '../../lib/utils/helpers' -import NumberInput from '../../components/NumberInput' import DeceasedShare from '../../components/DeceasedShare' type RepeaterProps = { @@ -61,7 +60,7 @@ export const ReportFieldsRepeater: FC< const { id, props } = field - const deceasedHadAssets = getDeceasedHadAssets(application) + const deceasedHadAssets = getDeceasedWasMarriedAndHadAssets(application) const { fields, append, remove, replace } = useFieldArray({ name: id, @@ -119,13 +118,8 @@ export const ReportFieldsRepeater: FC< calculateTotal() }, [calculateTotal]) - const relations = - (externalData.syslumennOnEntry?.data as any).relationOptions?.map( - (relation: any) => ({ - value: relation, - label: relation, - }), - ) || [] + //TODO: connect to API + const debtTypes = [] as any const handleAddRepeaterFields = () => { //reset stocks @@ -388,15 +382,17 @@ export const ReportFieldsRepeater: FC< suffix="%" required /> - ) : field.id === 'relation' ? ( + ) : field.id === 'debtType' ? ( - ) : field.id === 'exchangeRateOrInterest' ? ( + options={debtTypes} + backgroundColor="blue" + /> /* Commenting out for testing purposes of this field + + : field.id === 'exchangeRateOrInterest' ? ( + )*/ ) : ( { - const realEstateAssets = (answers.assets as unknown as EstateAssets) - ?.realEstate?.data - - return (realEstateAssets ?? []).map((asset) => { - const propertyValuation = parseFloat(asset.propertyValuation) - const propertyShare = parseFloat(asset.share) - - const description = [ - `${m.assetNumber.defaultMessage}: ${asset.assetNumber}`, - m.realEstateEstimation.defaultMessage + - ': ' + - (propertyValuation - ? formatCurrency(String(propertyValuation)) - : '0 kr.'), - m.propertyShare.defaultMessage + `: ${propertyShare}%`, - ] - - const deceasedShare = valueToNumber(asset.deceasedShare) - - if (hasYes(asset.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: asset.description, - description, - } - }) - }, - }, - ), - buildKeyValueField({ - label: m.realEstateEstimation, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.realEstate.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewVehicles', - title: m.vehicles, - titleVariant: 'h3', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: (application: Application) => { - const answers = application.answers - const vehicleAssets = (answers.assets as unknown as EstateAssets) - .vehicles.data - return ( - vehicleAssets.map((asset) => { - const description = [ - `${m.vehicleNumberLabel.defaultMessage}: ${asset.assetNumber}`, - m.vehicleValuation.defaultMessage + - ': ' + - (asset.propertyValuation - ? formatCurrency(asset.propertyValuation) - : '0 kr.'), - ] - - const deceasedShare = valueToNumber(asset.deceasedShare) - - if (hasYes(asset.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: asset.description, - description, - } - }) ?? [] - ) - }, - }, - ), - buildKeyValueField({ - label: m.marketValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.vehicles.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewGuns', - title: m.guns, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const gunAssets = (answers.assets as unknown as EstateAssets).guns.data - return ( - gunAssets.map((asset) => { - const description = [ - `${m.gunSerialNumber.defaultMessage}: ${asset.assetNumber}`, - m.gunValuation.defaultMessage + - ': ' + - (asset.propertyValuation - ? formatCurrency(asset.propertyValuation) - : '0 kr.'), - ] - - const deceasedShare = valueToNumber(asset.deceasedShare) - - if (hasYes(asset.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: asset.description, - description, - } - }) ?? [] - ) - }, - }, - ), - buildKeyValueField({ - label: m.marketValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.guns.total') - return total ? formatCurrency(String(total)) : '0 kr.' - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewInventory', - title: m.inventoryTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildDescriptionField({ - id: 'overviewInventory', - title: m.inventoryTextField, - description: (application: Application) => - getValueViaPath(application.answers, 'assets.inventory.info'), - titleVariant: 'h4', - space: 'gutter', - marginBottom: 'gutter', - condition: (answers) => - getValueViaPath(answers, 'assets.inventory.info') !== '', - }), - buildKeyValueField({ - label: m.marketValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.inventory.value') - return formatCurrency(String(total)) - }, - }), - buildKeyValueField({ - label: m.deceasedShare, - display: 'flex', - condition: shouldShowDeceasedShareField, - value: ({ answers }) => { - const deceasedShare = getValueViaPath( - answers, - 'assets.inventory.deceasedShare', - ) - return `${deceasedShare}%` - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewBanks', - title: m.estateBankInfo, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => - ( - (answers.assets as unknown as EstateAssets).bankAccounts.data ?? [] - ).map((account) => { - const isForeign = account.foreignBankAccount?.length - - const description = [ - `${m.bankAccountCapital.defaultMessage}: ${formatCurrency( - String(valueToNumber(account.propertyValuation)), - )}`, - `${ - m.bankAccountPenaltyInterestRates.defaultMessage - }: ${formatCurrency( - String(valueToNumber(account.exchangeRateOrInterest)), - )}`, - `${m.bankAccountForeign.defaultMessage}: ${ - isForeign ? m.yes.defaultMessage : m.no.defaultMessage - }`, - ] - - const deceasedShare = valueToNumber(account.deceasedShare) - - if (hasYes(account.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - titleRequired: false, - title: isForeign - ? account.assetNumber - : formatBankInfo(account.assetNumber ?? ''), - description, - } - }), - }, - ), - buildKeyValueField({ - label: m.banksBalance, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.bankAccounts.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewClaims', - title: m.claimsTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const claims = (answers.assets as unknown as EstateAssets).claims.data - return ( - claims.map((asset: ClaimsData) => { - const description = [ - m.claimsAmount.defaultMessage + - ': ' + - (asset.value ? formatCurrency(asset.value) : '0 kr.'), - ] - - const deceasedShare = valueToNumber(asset.deceasedShare) - - if (hasYes(asset.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: asset.description, - titleRequired: false, - description, - } - }) ?? [] - ) - }, - }, - ), - buildKeyValueField({ - label: m.totalValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.claims.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewStocks', - title: m.stocksTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const stocks = (answers.assets as unknown as EstateAssets).stocks.data - return ( - stocks.map((stock: StocksData) => { - const description = [ - `${m.stocksNationalId.defaultMessage}: ${formatNationalId( - stock.nationalId ?? '', - )}`, - `${m.stocksFaceValue.defaultMessage}: ${formatCurrency( - stock.amount ?? '0', - )}`, - `${m.stocksRateOfChange.defaultMessage}: ${ - stock.exchangeRateOrInterest?.replace('.', ',') ?? '0' - }`, - `${m.stocksValue.defaultMessage}: ${formatCurrency( - stock.value ?? '0', - )}`, - ] - - const deceasedShare = valueToNumber(stock.deceasedShare) - - if (hasYes(stock.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: stock.organization, - titleRequired: false, - description, - } - }) ?? [] - ) - }, - }, - ), - buildKeyValueField({ - label: m.totalValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.stocks.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewMoney', - title: m.moneyTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildDescriptionField({ - id: 'moneyInfo', - title: m.moneyText, - description: (application: Application) => - getValueViaPath(application.answers, 'assets.money.info'), - titleVariant: 'h4', - space: 'gutter', - marginBottom: 'gutter', - condition: (answers) => - getValueViaPath(answers, 'assets.money.info') !== '', - }), - buildKeyValueField({ - label: m.totalValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.money.value') - return formatCurrency(String(total)) - }, - }), - buildKeyValueField({ - label: m.deceasedShare, - display: 'flex', - condition: shouldShowDeceasedShareField, - value: ({ answers }) => { - const deceasedShare = getValueViaPath( - answers, - 'assets.money.deceasedShare', - ) - return `${deceasedShare}%` - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewOtherAssets', - title: m.otherAssetsTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'otherAssetsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const otherAssets = (answers.assets as unknown as EstateAssets) - .otherAssets.data - return ( - otherAssets.map((otherAsset: OtherAssetsData) => { - const description = [ - `${m.otherAssetsValue.defaultMessage}: ${formatCurrency( - otherAsset.value ?? '0', - )}`, - ] - - const deceasedShare = valueToNumber(otherAsset.deceasedShare) - - if (hasYes(otherAsset.deceasedShareEnabled)) { - description.push( - m.deceasedShare.defaultMessage + `: ${String(deceasedShare)}%`, - ) - } - - return { - title: otherAsset.info, - description, - } - }) ?? [] - ) - }, - }, - ), - buildKeyValueField({ - label: m.totalValue, - display: 'flex', - value: ({ answers }) => { - const total = getValueViaPath(answers, 'assets.otherAssets.total') - return formatCurrency(String(total)) - }, - }), - buildDividerField({}), - buildCustomField({ - title: '', - id: 'assets.assetsTotal', - doesNotRequireAnswer: true, - component: 'CalculateTotalAssets', - }), -] diff --git a/libs/application/templates/inheritance-report/src/forms/done.ts b/libs/application/templates/inheritance-report/src/forms/done.ts index 4620cd6563b7..67e457b25e80 100644 --- a/libs/application/templates/inheritance-report/src/forms/done.ts +++ b/libs/application/templates/inheritance-report/src/forms/done.ts @@ -1,9 +1,6 @@ -import { - buildForm, - buildCustomField, - buildMultiField, -} from '@island.is/application/core' +import { buildForm } from '@island.is/application/core' import { Form, FormModes } from '@island.is/application/types' +import { buildFormConclusionSection } from '@island.is/application/ui-forms' import { m } from '../lib/messages' export const done: Form = buildForm({ @@ -12,17 +9,13 @@ export const done: Form = buildForm({ mode: FormModes.COMPLETED, renderLastScreenButton: true, children: [ - buildMultiField({ - id: 'done', - title: m.doneTitle, - description: m.doneDescription, - children: [ - buildCustomField({ - id: 'doneImage', - component: 'DoneImage', - title: '', - }), - ], + buildFormConclusionSection({ + sectionTitle: '', + multiFieldTitle: '', + alertTitle: '', + alertMessage: '', + expandableHeader: '', + expandableDescription: '', }), ], }) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts b/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts index 713d358249e8..f3a7e5f8eb00 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts @@ -52,6 +52,7 @@ export const applicant = buildSection({ id: 'applicant.phone', title: m.phone, width: 'half', + required: true, format: '###-####', defaultValue: (application: Application) => { const phone = @@ -68,6 +69,7 @@ export const applicant = buildSection({ id: 'applicant.email', title: m.email, width: 'half', + required: true, defaultValue: ({ externalData }: Application) => { const data = externalData.userProfile?.data as UserProfile return data?.email @@ -77,6 +79,7 @@ export const applicant = buildSection({ id: 'applicant.relation', title: m.relation, width: 'half', + required: true, options: [ { label: m.heir, value: RelationEnum.HEIR }, { label: m.representative, value: RelationEnum.REPRESENTATIVE }, diff --git a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts index a9f44ed29ca6..ee20d38ee8fb 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts @@ -27,7 +27,7 @@ export const assets = buildSection({ description: m.propertiesDescription.defaultMessage + ' ' + - m.continueWithoutAssests.defaultMessage, + m.continueWithoutAssets.defaultMessage, children: [ buildDescriptionField({ id: 'realEstateTitle', @@ -53,35 +53,31 @@ export const assets = buildSection({ { fields: [ { - title: m.assetNumber.defaultMessage, + title: m.assetNumber, id: 'assetNumber', placeholder: 'F1234567', }, { - title: m.assetAddress.defaultMessage, + title: m.assetAddress, id: 'description', backgroundColor: 'white', readOnly: true, }, { - title: m.propertyShare.defaultMessage, + title: m.propertyShare, id: 'share', type: 'number', - defaultValue: '100', suffix: '%', - required: true, }, { - title: m.propertyValuation.defaultMessage, + title: m.propertyValuation, id: 'propertyValuation', - required: true, currency: true, }, ], assetKey: 'assets', calcWithShareValue: true, - repeaterButtonText: m.addRealEstate.defaultMessage, - fromExternalData: 'assets', + repeaterButtonText: m.addRealEstate, sumField: 'propertyValuation', }, ), @@ -99,7 +95,7 @@ export const assets = buildSection({ description: m.propertiesDescription.defaultMessage + ' ' + - m.continueWithoutInnventory.defaultMessage, + m.continueWithoutInventory.defaultMessage, children: [ buildDescriptionField({ id: 'inventoryTitle', @@ -119,7 +115,8 @@ export const assets = buildSection({ ?.inheritanceReportInfo?.cash?.[0]?.description ?? '' ) }, - rows: 7, + rows: 4, + maxLength: 1800, }), buildTextField({ id: 'assets.inventory.value', @@ -254,7 +251,6 @@ export const assets = buildSection({ { title: m.gunSerialNumber, id: 'assetNumber', - placeholder: 'VantarHér', required: true, }, { @@ -331,7 +327,7 @@ export const assets = buildSection({ { title: m.bankAccountPenaltyInterestRates, id: 'exchangeRateOrInterest', - required: false, + required: true, currency: true, }, { @@ -397,6 +393,7 @@ export const assets = buildSection({ { title: m.nationalId, id: 'assetNumber', + type: 'nationalId', format: '######-####', }, { @@ -462,11 +459,13 @@ export const assets = buildSection({ title: m.stocksFaceValue, id: 'amount', currency: true, + required: true, }, { title: m.stocksRateOfChange, id: 'exchangeRateOrInterest', type: 'number', + required: true, }, { title: m.stocksValue, @@ -515,7 +514,8 @@ export const assets = buildSection({ ?.description ?? '' ) }, - rows: 7, + rows: 4, + maxLength: 1800, }), buildTextField({ id: 'assets.money.value', diff --git a/libs/application/templates/inheritance-report/src/forms/sections/dataCollection.ts b/libs/application/templates/inheritance-report/src/forms/sections/dataCollection.ts index f86fa2ba5a49..755a78c71634 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/dataCollection.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/dataCollection.ts @@ -20,30 +20,23 @@ export const dataCollection = buildSection({ checkboxLabel: m.dataCollectionCheckbox, dataProviders: [ buildDataProviderItem({ - //provider: TBD, title: m.deceasedInfoProviderTitle, subTitle: m.deceasedInfoProviderSubtitle, }), + buildDataProviderItem({ + title: m.financialInformationProviderTitle, + subTitle: m.financialInformationProviderSubtitle, + }), buildDataProviderItem({ provider: NationalRegistryUserApi, title: m.personalInfoProviderTitle, subTitle: m.personalInfoProviderSubtitle, }), - buildDataProviderItem({ - //provider: TBD, - title: m.financialInformationProviderTitle, - subTitle: m.financialInformationProviderSubtitle, - }), buildDataProviderItem({ provider: UserProfileApi, title: m.settingsInfoProviderTitle, subTitle: m.settingsInfoProviderSubtitle, }), - buildDataProviderItem({ - //TODO: provider: TBD, - title: m.funeralExpensesTitle, - subTitle: m.funeralExpensesSubtitle, - }), ], }), ], diff --git a/libs/application/templates/inheritance-report/src/forms/sections/debtsAndFuneralCost.ts b/libs/application/templates/inheritance-report/src/forms/sections/debtsAndFuneralCost.ts index 59ab7668bb46..0e5c1ba99461 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/debtsAndFuneralCost.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/debtsAndFuneralCost.ts @@ -1,21 +1,11 @@ import { buildCustomField, buildDescriptionField, - buildDividerField, - buildKeyValueField, buildMultiField, buildSection, buildSubSection, - buildTextField, - getValueViaPath, } from '@island.is/application/core' -import { Application } from '@island.is/application/types' -import { format as formatNationalId } from 'kennitala' -import { formatCurrency } from '@island.is/application/ui-components' import { m } from '../../lib/messages' -import { ApplicationDebts, Debt } from '../../types' -import { getEstateDataFromApplication } from '../../lib/utils/helpers' -import { YES } from '../../lib/constants' export const debtsAndFuneralCost = buildSection({ id: 'debts', @@ -57,6 +47,10 @@ export const debtsAndFuneralCost = buildSection({ id: 'nationalId', format: '######-####', }, + { + title: m.debtType, + id: 'debtType', + }, { title: m.debtsLoanIdentity, id: 'assetNumber', @@ -74,31 +68,6 @@ export const debtsAndFuneralCost = buildSection({ sumField: 'propertyValuation', }, ), - buildDescriptionField({ - id: 'publicChargesHeader', - title: m.publicChargesTitle, - description: m.publicChargesDescription, - titleVariant: 'h3', - space: 'containerGutter', - marginBottom: 'gutter', - }), - buildDescriptionField({ - id: 'debts.publicCharges.total', - title: '', - }), - buildTextField({ - title: m.amount.defaultMessage, - id: 'debts.publicCharges', - width: 'half', - variant: 'currency', - defaultValue: (application: Application) => { - return ( - getEstateDataFromApplication(application) - ?.inheritanceReportInfo?.officialFees?.[0] - ?.propertyValuation ?? '0' - ) - }, - }), ], }), ], @@ -173,238 +142,19 @@ export const debtsAndFuneralCost = buildSection({ }), buildSubSection({ id: 'debtsAndFuneralCostOverview', - title: m.debtsAndFuneralCostOverview, + title: m.overview, children: [ buildMultiField({ id: 'debtsAndFuneralCostOverview', title: m.debtsAndFuneralCostOverview, description: m.overviewDescription, children: [ - buildDividerField({}), - buildDescriptionField({ - id: 'overviewDomesticAndForeignDebts', - title: m.debtsTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'estateDebtsCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const allDebts = ( - answers.debts as unknown as ApplicationDebts - ).domesticAndForeignDebts.data - return ( - allDebts.map((debt: Debt) => ({ - title: debt.description ?? '', - description: [ - `${m.nationalId.defaultMessage}: ${formatNationalId( - debt.nationalId ?? '', - )}`, - `${m.debtsLoanIdentity.defaultMessage}: ${ - debt.assetNumber ?? '' - }`, - `${m.debtsBalance.defaultMessage}: ${formatCurrency( - debt.propertyValuation ?? '0', - )}`, - ], - })) ?? [] - ) - }, - }, - ), - buildDividerField({}), - buildKeyValueField({ - label: m.totalAmountDebts, - display: 'flex', - value: ({ answers }) => - formatCurrency( - String( - getValueViaPath( - answers, - 'debts.domesticAndForeignDebts.total', - ), - ), - ), - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewPublicCharges', - title: m.publicChargesTitle, - titleVariant: 'h3', - marginBottom: 'gutter', - space: 'gutter', - }), - buildCustomField( - { - title: '', - id: 'chargesCards', - component: 'Cards', - doesNotRequireAnswer: true, - }, - { - cards: ({ answers }: Application) => { - const publicCharges = ( - answers.debts as unknown as ApplicationDebts - ).publicCharges - return publicCharges - ? [ - { - title: m.publicChargesTitle.defaultMessage, - description: [`${formatCurrency(publicCharges)}`], - }, - ] - : [] - }, - }, - ), - buildDividerField({}), - buildKeyValueField({ - label: m.totalAmountPublic, - display: 'flex', - value: ({ answers }) => { - const value = - getValueViaPath(answers, 'debts.publicCharges') || '0' - return formatCurrency(value) - }, - }), - buildDividerField({}), - buildDescriptionField({ - id: 'overviewFuneralCost', - title: m.funeralCostTitle, - titleVariant: 'h3', - marginBottom: 'p3', - space: 'containerGutter', - }), - buildKeyValueField({ - label: m.funeralBuildCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.build') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralCremationCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.cremation') || - '0', - ), - }), - buildKeyValueField({ - label: m.funeralPrintCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.print') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralFlowersCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.flowers') || - '0', - ), - }), - buildKeyValueField({ - label: m.funeralMusicCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.music') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralRentCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.rent') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralFoodAndDrinkCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.food') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralTombstoneCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.tombstone') || - '0', - ), - }), - buildKeyValueField({ - label: m.funeralOtherCostQuestion, - display: 'flex', - condition: (answers) => - !getValueViaPath( - answers, - 'funeralCost.hasOther', - )?.includes(YES), - value: ({ answers }) => - getValueViaPath( - answers, - 'funeralCost.hasOther', - )?.includes(YES) - ? m.yes - : m.no, - }), - buildKeyValueField({ - label: m.funeralOtherCost, - display: 'flex', - condition: (answers) => - !!getValueViaPath( - answers, - 'funeralCost.hasOther', - )?.includes(YES), - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.other') || '0', - ), - }), - buildKeyValueField({ - label: m.funeralOtherCostDetailsOverview, - display: 'block', - condition: (answers) => - !!getValueViaPath( - answers, - 'funeralCost.hasOther', - )?.includes(YES), - value: ({ answers }) => { - return ( - getValueViaPath( - answers, - 'funeralCost.otherDetails', - ) || '' - ) - }, - }), - buildDividerField({}), - buildKeyValueField({ - label: m.totalAmountFuneralCost, - display: 'flex', - value: ({ answers }) => - formatCurrency( - getValueViaPath(answers, 'funeralCost.total') || '0', - ), + buildCustomField({ + title: '', + description: '', + id: 'overviewDebts', + component: 'OverviewDebts', }), - buildDividerField({}), buildCustomField({ title: '', id: 'debts.debtsTotal', diff --git a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts index a4bc9780f3ff..1dd18ffe0fd0 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts @@ -4,6 +4,7 @@ import { buildMultiField, buildRadioField, buildSection, + buildTextField, getValueViaPath, } from '@island.is/application/core' import { m } from '../../lib/messages' @@ -96,6 +97,37 @@ export const deceased = buildSection({ { value: NO, label: m.no }, ], }), + buildDescriptionField({ + id: 'space4', + space: 'gutter', + title: '', + }), + buildRadioField({ + id: 'customShare.hasCustomSpouseSharePercentage', + title: m.hasCustomSpouseSharePercentage, + largeButtons: false, + backgroundColor: 'white', + width: 'half', + condition: (answers) => + getValueViaPath(answers, 'deceasedWasMarried') === YES, + options: [ + { value: YES, label: m.spouseSharePart }, + { value: NO, label: m.spouseShareFull }, + ], + }), + buildTextField({ + id: 'customShare.customSpouseSharePercentage', + title: m.deceasedShare, + width: 'half', + placeholder: '50%', + suffix: '%', + variant: 'number', + condition: (answers) => + getValueViaPath( + answers, + 'customShare.hasCustomSpouseSharePercentage', + ) === YES, + }), ], }), ], diff --git a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts index 6f5438b4696e..1053f617fbdf 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts @@ -1,5 +1,4 @@ import { - buildCheckboxField, buildCustomField, buildDescriptionField, buildDividerField, @@ -19,7 +18,6 @@ import { shouldShowCustomSpouseShare, valueToNumber, } from '../../lib/utils/helpers' -import { YES } from '../../lib/constants' export const heirs = buildSection({ id: 'heirs', @@ -66,20 +64,6 @@ export const heirs = buildSection({ id: 'customShare.customSpouseSharePercentage', title: '', }), - buildCheckboxField({ - id: 'customShare.hasCustomSpouseSharePercentage', - title: '', - large: false, - backgroundColor: 'white', - defaultValue: [], - condition: shouldShowCustomSpouseShare, - options: [ - { - value: YES, - label: m.assetsToShareHasCustomSpousePercentage, - }, - ], - }), buildCustomField({ title: '', id: 'share', @@ -177,11 +161,11 @@ export const heirs = buildSection({ title: '', placeholder: m.infoPlaceholder, variant: 'textarea', - rows: 5, + rows: 4, maxLength: 1800, }), buildDescriptionField({ - id: 'heirsAdditionalInfoFiles', + id: 'heirsAdditionalInfoFilesPrivateTitle', title: m.fileUploadPrivateTransfer, titleVariant: 'h5', space: 'containerGutter', @@ -189,25 +173,25 @@ export const heirs = buildSection({ }), buildFileUploadField({ id: 'heirsAdditionalInfoPrivateTransferFiles', + uploadAccept: '.pdf, .doc, .docx, .jpg, .jpeg, .png, .xls, .xlsx', + uploadDescription: m.fileUploadFileTypes, uploadMultiple: false, title: '', - description: '', uploadHeader: '', - uploadDescription: '', }), buildDescriptionField({ - id: 'heirsAdditionalInfoFiles', + id: 'heirsAdditionalInfoFilesOtherDocumentsTitle', title: m.fileUploadOtherDocuments, titleVariant: 'h5', space: 'containerGutter', marginBottom: 'smallGutter', }), buildFileUploadField({ - id: 'heirsAdditionalInfoFiles', + id: 'heirsAdditionalInfoFilesOtherDocuments', + uploadAccept: '.pdf, .doc, .docx, .jpg, .jpeg, .png, .xls, .xlsx', + uploadDescription: m.fileUploadFileTypes, title: '', - description: '', uploadHeader: '', - uploadDescription: '', }), ], }), @@ -219,7 +203,8 @@ export const heirs = buildSection({ children: [ buildMultiField({ id: 'heirsOverview', - title: m.overview, + title: m.overviewHeirsTitle, + description: m.overviewHeirsDescription, children: [ buildDividerField({}), buildDescriptionField({ @@ -398,6 +383,36 @@ export const heirs = buildSection({ value: ({ answers }) => getValueViaPath(answers, 'heirsAdditionalInfo'), }), + buildDescriptionField({ + id: 'heirs_space5', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.fileUploadPrivateTransfer, + value: ({ answers }) => { + const file = getValueViaPath( + answers, + 'heirsAdditionalInfoPrivateTransferFiles', + )?.[0] + return file?.name + }, + }), + buildDescriptionField({ + id: 'heirs_space6', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.fileUploadOtherDocuments, + value: ({ answers }) => { + const files = getValueViaPath( + answers, + 'heirsAdditionalInfoFilesOtherDocuments', + ) + return files.map((file: any) => file.name).join(', ') + }, + }), buildCustomField({ title: '', id: 'overviewPrint', diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index cf117d2a58ec..3c464403435b 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -28,7 +28,7 @@ const validateDeceasedShare = ({ deceasedShareEnabled.includes(YES) ) { const value = valueToNumber(deceasedShare) - return value > 0 && value <= 100 + return value >= 0 && value <= 100 } return true @@ -80,7 +80,7 @@ const assetSchema = ({ withShare }: { withShare?: boolean } = {}) => const value = isNaN(num) ? 0 : num - return value >= 0 && value <= 100 + return value > 0 && value <= 100 } return true @@ -318,7 +318,7 @@ export const inheritanceReportSchema = z.object({ .object({ description: z.string(), nationalId: z.string(), - assetNumber: z.string().refine((v) => validateDebtBankAccount(v)), + assetNumber: z.string(), //.refine((v) => validateDebtBankAccount(v)), propertyValuation: z.string(), }) .refine( @@ -437,7 +437,7 @@ export const inheritanceReportSchema = z.object({ if (!v) return true const num = parseInt(v, 10) ?? 0 - return num > -1 && num < 101 + return num > 0 && num < 101 }), taxFreeInheritance: z.string(), inheritance: z.string(), @@ -593,15 +593,12 @@ export const inheritanceReportSchema = z.object({ netPropertyForExchange: z.number(), customShare: z .object({ - hasCustomSpouseSharePercentage: z.array(z.enum([YES])).optional(), - customSpouseSharePercentage: z.string(), + hasCustomSpouseSharePercentage: z.string().optional(), + customSpouseSharePercentage: z.string().optional(), }) .refine( ({ hasCustomSpouseSharePercentage, customSpouseSharePercentage }) => { - if ( - hasCustomSpouseSharePercentage && - hasCustomSpouseSharePercentage.length > 0 - ) { + if (hasCustomSpouseSharePercentage === YES) { const val = valueToNumber(customSpouseSharePercentage) return val >= 50 && val <= 100 } @@ -614,8 +611,6 @@ export const inheritanceReportSchema = z.object({ }, ) .optional(), - - /* einkaskipti */ confirmAction: z.array(z.enum([YES])).length(1), }) diff --git a/libs/application/templates/inheritance-report/src/lib/messages.ts b/libs/application/templates/inheritance-report/src/lib/messages.ts index 6f996b7fff4e..d5b8a29d4e2b 100644 --- a/libs/application/templates/inheritance-report/src/lib/messages.ts +++ b/libs/application/templates/inheritance-report/src/lib/messages.ts @@ -150,17 +150,6 @@ export const m = defineMessages({ 'Persónustillingar þínar (sími og netfang) þínar frá Ísland.is.', description: '', }, - funeralExpensesTitle: { - id: 'ir.application:funeralExpensesTitle', - defaultMessage: 'Yfirlit um útfararkostnað', - description: '', - }, - funeralExpensesSubtitle: { - id: 'ir.application:funeralExpensesSubtitle', - defaultMessage: - 'Athugað er hvort að skráningaraðili sé búinn að fylla út yfirlit um útfararkostnað', - description: '', - }, // Applicant's Information applicantsInfo: { @@ -276,8 +265,8 @@ export const m = defineMessages({ 'Vinsamlegast tilgreindu allar hjúskapareignir beggja hjóna utan einstaklingsatvinnurekstrar á dánardegi hins látna. Einnig séreign hins látna.', description: '', }, - continueWithoutAssests: { - id: 'ir.application:continueWithoutAssests', + continueWithoutAssets: { + id: 'ir.application:continueWithoutAssets', defaultMessage: 'Ef hinn látni átti ekki fasteign vinsamlegast haltu áfram í ferlinu.', description: '', @@ -294,8 +283,8 @@ export const m = defineMessages({ 'Ef hinn látni átti ekki skotvopn vinsamlegast haltu áfram í ferlinu.', description: '', }, - continueWithoutInnventory: { - id: 'ir.application:continueWithoutInnventory', + continueWithoutInventory: { + id: 'ir.application:continueWithoutInventory', defaultMessage: 'Ef hinn látni átti ekki innbú vinsamlegast haltu áfram í ferlinu.', description: '', @@ -718,7 +707,7 @@ export const m = defineMessages({ }, debtsAndFuneralCostOverview: { id: 'ir.application:debtsAndFuneralCostOverview', - defaultMessage: 'Yfirlit', + defaultMessage: 'Yfirlit skulda og útfararkostnaðar', description: '', }, assetOverviewDescription: { @@ -891,6 +880,11 @@ export const m = defineMessages({ defaultMessage: 'Auðkenni / Lánsnúmer', description: '', }, + debtType: { + id: 'ir.application:debtsType', + defaultMessage: 'Tegund skuldar', + description: '', + }, creditorsNationalId: { id: 'ir.application:creditorsNationalId', defaultMessage: 'Kennitala', @@ -1112,6 +1106,21 @@ export const m = defineMessages({ defaultMessage: 'Var hinn látni í hjúskap?', description: '', }, + hasCustomSpouseSharePercentage: { + id: 'ir.application:hasCustomSpouseSharePercentage', + defaultMessage: 'Er verið að skipta dánarbúi að fullu eða að hluta?', + description: '', + }, + spouseShareFull: { + id: 'ir.application:spouseShareFull', + defaultMessage: 'Að fullu', + description: '', + }, + spouseSharePart: { + id: 'ir.application:spouseSharePart', + defaultMessage: 'Að hluta', + description: '', + }, hadSeparateProperty: { id: 'ir.application:hadSeparateProperty', defaultMessage: @@ -1390,6 +1399,12 @@ export const m = defineMessages({ defaultMessage: 'Einkaskiptagerð', description: '', }, + fileUploadFileTypes: { + id: 'ir.application:fileUploadFileTypes', + defaultMessage: + 'Samþykktar skráargerðir eru .pdf, .doc, .docx, .jpg, .jpeg, .png, .xls og .xlsx', + description: '', + }, fileUploadOtherDocuments: { id: 'ir.application:fileUploadOtherDocuments', defaultMessage: 'Önnur fylgigögn', @@ -1446,6 +1461,16 @@ export const m = defineMessages({ defaultMessage: 'Prenta yfirlit', description: '', }, + overviewHeirsTitle: { + id: 'ir.application:overviewHeirsTitle', + defaultMessage: 'Yfirlit erfingja', + description: '', + }, + overviewHeirsDescription: { + id: 'ir.application:overviewHeirsDescription', + defaultMessage: 'Yfirlit yfir erfingja og skiptingu', + description: '', + }, // Done beforeSubmitStatement: { @@ -1509,7 +1534,7 @@ export const m = defineMessages({ errorPropertyNumber: { id: 'ir.application:error.errorPropertyNumber', defaultMessage: - 'Verður að innihalda 6 tölustafi eða L + 6 fyrir landeignanúmeri, 7 tölustafi, F + 7 fyrir fasteignanúmeri', + 'Verður að innihalda 6 tölustafi eða L + 6 fyrir landeignanúmer, 7 tölustafi eða F + 7 fyrir fasteignanúmer', description: 'Property number is invalid', }, }) diff --git a/libs/application/templates/inheritance-report/src/types.ts b/libs/application/templates/inheritance-report/src/types.ts index 1b4c7ba570d9..638df5a1c4d7 100644 --- a/libs/application/templates/inheritance-report/src/types.ts +++ b/libs/application/templates/inheritance-report/src/types.ts @@ -215,6 +215,7 @@ export interface Debt { nationalId: string description: string propertyValuation: string + debtType: string } export interface ApplicationDebts { diff --git a/libs/application/templates/inheritance-report/src/types/index.ts b/libs/application/templates/inheritance-report/src/types/index.ts deleted file mode 100644 index 2e57ca5f223b..000000000000 --- a/libs/application/templates/inheritance-report/src/types/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -export enum DataProviderTypes { - NationalRegistry = 'NationalRegistryProvider', -} - -export interface Address { - streetName: string - postalCode: string - city: string -} - -export interface Person { - nationalId: string - fullName: string - address: Address -} - -export interface Child { - nationalId: string - livesWithApplicant: boolean - livesWithBothParents: boolean - fullName: string - otherParent: Person - custodyParents?: string[] -} - -export interface NationalRegistry extends Person { - children: Child[] -} From e932e2e682d683c2f5be53a144ef8203a0cabef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3rey=20J=C3=B3na?= Date: Thu, 30 May 2024 10:31:03 +0000 Subject: [PATCH 13/82] fix(native-app): notifications minor fixes (#14998) * fix: remove unused code * fix: show loading when fetching on notifications screen * fix: icon size and cache update * fix: don't show spinner when initially loading * fix: use for - of instead of forEach in loop --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../screens/notifications/notifications.tsx | 54 +++++++------------ .../app/src/screens/settings/settings.tsx | 1 - apps/native/app/src/ui/lib/button/button.tsx | 2 +- 3 files changed, 21 insertions(+), 36 deletions(-) diff --git a/apps/native/app/src/screens/notifications/notifications.tsx b/apps/native/app/src/screens/notifications/notifications.tsx index 208655e1a3cf..f496cab9a3e5 100644 --- a/apps/native/app/src/screens/notifications/notifications.tsx +++ b/apps/native/app/src/screens/notifications/notifications.tsx @@ -5,7 +5,7 @@ import { Skeleton, Problem, } from '@ui' -import { Reference, useApolloClient } from '@apollo/client' +import { useApolloClient } from '@apollo/client' import { dismissAllNotificationsAsync } from 'expo-notifications' import React, { useCallback, useEffect, useMemo, useState } from 'react' @@ -87,40 +87,22 @@ export const NotificationsScreen: NavigationFunctionComponent = ({ const [markAllUserNotificationsAsRead] = useMarkAllNotificationsAsReadMutation({ - onCompleted: (data) => { - if (data.markAllNotificationsRead?.success) { + onCompleted: (d) => { + if (d.markAllNotificationsRead?.success) { // If all notifications are marked as read, update cache to reflect that - client.cache.modify({ - fields: { - userNotifications(existingNotifications = {}) { - const existingDataRefs = existingNotifications.data || [] - - const updatedData = existingDataRefs.forEach( - (ref: Reference | NotificationItem) => { - const id = client.cache.identify(ref) - client.cache.modify({ - id, - fields: { - metadata(existingMetadata) { - return { - ...existingMetadata, - read: false, - } - }, - }, - }) - return ref - }, - ) - - return { - ...existingNotifications, - data: updatedData, - unreadCount: 0, - } + for (const notification of data?.userNotifications?.data || []) { + client.cache.modify({ + id: client.cache.identify(notification), + fields: { + metadata(existingMetadata) { + return { + ...existingMetadata, + read: true, + } + }, }, - }, - }) + }) + } } }, }) @@ -251,6 +233,7 @@ export const NotificationsScreen: NavigationFunctionComponent = ({ title={intl.formatMessage({ id: 'notifications.screenTitle' })} onClosePress={() => Navigation.dismissModal(componentId)} style={{ marginHorizontal: 16 }} + showLoading={loading && !!data} /> @@ -281,7 +264,10 @@ export const NotificationsScreen: NavigationFunctionComponent = ({ style={{ maxWidth: 145, }} - iconStyle={{ tintColor: theme.color.blue400 }} + iconStyle={{ + tintColor: theme.color.blue400, + resizeMode: 'contain', + }} /> {showError ? ( diff --git a/apps/native/app/src/screens/settings/settings.tsx b/apps/native/app/src/screens/settings/settings.tsx index 59473d9c2035..c63bcadacf9d 100644 --- a/apps/native/app/src/screens/settings/settings.tsx +++ b/apps/native/app/src/screens/settings/settings.tsx @@ -39,7 +39,6 @@ import { createNavigationOptionHooks } from '../../hooks/create-navigation-optio import { navigateTo } from '../../lib/deep-linking' import { showPicker } from '../../lib/show-picker' import { authStore } from '../../stores/auth-store' -import { useNotificationsStore } from '../../stores/notifications-store' import { preferencesStore, usePreferencesStore, diff --git a/apps/native/app/src/ui/lib/button/button.tsx b/apps/native/app/src/ui/lib/button/button.tsx index 98764be7a21e..db882a0c1a7e 100644 --- a/apps/native/app/src/ui/lib/button/button.tsx +++ b/apps/native/app/src/ui/lib/button/button.tsx @@ -92,7 +92,7 @@ const Text = styled.Text<{ const Icon = styled.Image` width: 16px; height: 16px; - margin-left: 10px; + margin-left: 8px; ` export function Button({ From 0901b5c7d9584433885aa4372aa5263b3b9dd89f Mon Sep 17 00:00:00 2001 From: MargretFinnboga <62568905+MargretFinnboga@users.noreply.github.com> Date: Thu, 30 May 2024 10:39:03 +0000 Subject: [PATCH 14/82] feat(fa): Adding to status page children aid amount (#15004) * adding sortable feature * Revert "adding sortable feature" This reverts commit d9691c54de2c2fb244cf89e49c0bfe6cd7857603. * adding more detail for api * removing white space break just adding html element to the db * adding childrenAidAmount to status * updating text --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/lib/models/amount.model.ts | 3 +++ .../src/fields/ChildrenForm/ChildrenForm.tsx | 6 +++--- .../src/fields/Status/ApplicantStatus.tsx | 7 ------- .../financial-aid/src/lib/hooks/useApplication.ts | 1 + .../financial-aid/src/lib/messages/childrenForm.ts | 14 +++++++------- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/libs/api/domains/municipalities-financial-aid/src/lib/models/amount.model.ts b/libs/api/domains/municipalities-financial-aid/src/lib/models/amount.model.ts index f8f366ec8a0e..795fe5053e76 100644 --- a/libs/api/domains/municipalities-financial-aid/src/lib/models/amount.model.ts +++ b/libs/api/domains/municipalities-financial-aid/src/lib/models/amount.model.ts @@ -9,6 +9,9 @@ export class AmountModel { @Field() readonly aidAmount!: number + @Field({ nullable: true }) + readonly childrenAidAmount?: number + @Field({ nullable: true }) readonly income!: number diff --git a/libs/application/templates/financial-aid/src/fields/ChildrenForm/ChildrenForm.tsx b/libs/application/templates/financial-aid/src/fields/ChildrenForm/ChildrenForm.tsx index 4b7ec227cdf1..37fc08ac83a0 100644 --- a/libs/application/templates/financial-aid/src/fields/ChildrenForm/ChildrenForm.tsx +++ b/libs/application/templates/financial-aid/src/fields/ChildrenForm/ChildrenForm.tsx @@ -63,6 +63,9 @@ const ChildrenForm = ({ application, field, errors }: FAFieldBaseProps) => { {formatMessage(childrenForm.page.commentTitle)} + + {formatMessage(childrenForm.page.commentText)} +
{ id={summaryCommentType} name={summaryCommentType} label={formatMessage(childrenForm.inputs.commentLabel)} - placeholder={formatMessage( - childrenForm.inputs.commentPlaceholder, - )} value={value} textarea={true} rows={8} diff --git a/libs/application/templates/financial-aid/src/fields/Status/ApplicantStatus.tsx b/libs/application/templates/financial-aid/src/fields/Status/ApplicantStatus.tsx index 1eaa3547bfbb..bfadba2f1fbc 100644 --- a/libs/application/templates/financial-aid/src/fields/Status/ApplicantStatus.tsx +++ b/libs/application/templates/financial-aid/src/fields/Status/ApplicantStatus.tsx @@ -37,17 +37,14 @@ const ApplicantStatus = ({ application, goToScreen }: FAFieldBaseProps) => { return (
- {isWaitingForSpouse && ( )} - {state === ApplicationState.APPROVED && ( )} - {state === ApplicationState.REJECTED && ( { email={municipality.data?.email} /> )} - {state === ApplicationState.DATANEEDED && ( )} - {state !== ApplicationState.REJECTED && ( { amount={currentApplication?.amount} /> )} - { : currentApplication?.spouseNationalId != null } /> - Date: Thu, 30 May 2024 11:17:04 +0000 Subject: [PATCH 15/82] fix(SGS): Adding skip payment for 65 and older for renewing licence plates (#15010) * added check for age for payment * still working on this * continue work * help me * skip payment change for renew plate * cleanup * cleaning up * More cleanup * new line --------- Co-authored-by: berglindoma13 Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../license-plate-renewal.service.ts | 65 ++++++++++++++----- .../src/lib/LicensePlateRenewalTemplate.ts | 23 +++++-- .../license-plate-renewal/src/utils/index.ts | 17 ++--- .../src/utils/isPaymentRequired.ts | 17 +++++ 4 files changed, 90 insertions(+), 32 deletions(-) create mode 100644 libs/application/templates/transport-authority/license-plate-renewal/src/utils/isPaymentRequired.ts diff --git a/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/license-plate-renewal/license-plate-renewal.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/license-plate-renewal/license-plate-renewal.service.ts index 6168557b9732..a53ab7eae0c5 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/license-plate-renewal/license-plate-renewal.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/license-plate-renewal/license-plate-renewal.service.ts @@ -10,6 +10,7 @@ import { VehiclePlateRenewalClient, } from '@island.is/clients/transport-authority/vehicle-plate-renewal' import { TemplateApiError } from '@island.is/nest/problem' +import { info } from 'kennitala' import { error } from '@island.is/application/templates/transport-authority/license-plate-renewal' @Injectable() @@ -25,7 +26,6 @@ export class LicensePlateRenewalService extends BaseTemplateApiService { const result = await this.vehiclePlateRenewalClient.getMyPlateOwnerships( auth, ) - // Validate that user has at least 1 plate ownership if (!result || !result.length) { throw new TemplateApiError( @@ -91,24 +91,18 @@ export class LicensePlateRenewalService extends BaseTemplateApiService { async submitApplication({ application, auth, + currentUserLocale, }: TemplateApiModuleActionProps): Promise { - const { paymentUrl } = application.externalData.createCharge.data as { - paymentUrl: string - } - if (!paymentUrl) { - throw new Error( - 'Ekki er búið að staðfesta greiðslu, hinkraðu þar til greiðslan er staðfest.', - ) + const age = info(auth.nationalId).age + if (age < 65 && application.state === 'draft') { + return } - const isPayment: { fulfilled: boolean } | undefined = - await this.sharedTemplateAPIService.getPaymentStatus(auth, application.id) - - if (!isPayment?.fulfilled) { - throw new Error( - 'Ekki er búið að staðfesta greiðslu, hinkraðu þar til greiðslan er staðfest.', - ) - } + await this.handlePayment({ + application, + auth, + currentUserLocale, + }) const answers = application.answers as LicensePlateRenewalAnswers const regno = answers?.pickPlate?.regno @@ -116,4 +110,43 @@ export class LicensePlateRenewalService extends BaseTemplateApiService { // Submit the application await this.vehiclePlateRenewalClient.renewPlateOwnership(auth, regno) } + + private async handlePayment({ + application, + auth, + }: TemplateApiModuleActionProps): Promise { + const age = info(auth.nationalId).age + + if (age < 65) { + // 1. Validate payment + + // 1a. Make sure a paymentUrl was created + + const { paymentUrl = '', id: paymentId = '' } = (application.externalData + ?.createCharge?.data ?? {}) as { + paymentUrl: string + id: string + } + + if (!paymentUrl) { + throw new Error( + 'Ekki er búið að staðfesta greiðslu, hinkraðu þar til greiðslan er staðfest.', + ) + } + + // 1b. Make sure payment is fulfilled (has been paid) + const payment: { fulfilled: boolean } | undefined = + await this.sharedTemplateAPIService.getPaymentStatus( + auth, + application.id, + ) + if (!payment?.fulfilled) { + throw new Error( + 'Ekki er búið að staðfesta greiðslu, hinkraðu þar til greiðslan er staðfest.', + ) + } + return paymentId + } + return null + } } diff --git a/libs/application/templates/transport-authority/license-plate-renewal/src/lib/LicensePlateRenewalTemplate.ts b/libs/application/templates/transport-authority/license-plate-renewal/src/lib/LicensePlateRenewalTemplate.ts index 16df29099f0d..52194f92cf09 100644 --- a/libs/application/templates/transport-authority/license-plate-renewal/src/lib/LicensePlateRenewalTemplate.ts +++ b/libs/application/templates/transport-authority/license-plate-renewal/src/lib/LicensePlateRenewalTemplate.ts @@ -30,6 +30,7 @@ import { AuthDelegationType } from '@island.is/shared/types' import { ApiScope } from '@island.is/auth/scopes' import { buildPaymentState } from '@island.is/application/utils' import { getChargeItemCodes, getExtraData } from '../utils' +import { isPaymentRequired } from '../utils/isPaymentRequired' const determineMessageFromApplicationAnswers = (application: Application) => { const regno = getValueViaPath( @@ -84,9 +85,14 @@ const template: ApplicationTemplate< ], }, lifecycle: EphemeralStateLifeCycle, - onExit: defineTemplateApi({ - action: ApiActions.validateApplication, - }), + onExit: [ + defineTemplateApi({ + action: ApiActions.validateApplication, + }), + defineTemplateApi({ + action: ApiActions.submitApplication, + }), + ], roles: [ { id: Roles.APPLICANT, @@ -112,7 +118,16 @@ const template: ApplicationTemplate< ], }, on: { - [DefaultEvents.SUBMIT]: { target: States.PAYMENT }, + [DefaultEvents.SUBMIT]: [ + { + target: States.PAYMENT, + cond: (application) => isPaymentRequired(application), + }, + { + target: States.COMPLETED, + cond: (application) => !isPaymentRequired(application), + }, + ], }, }, [States.PAYMENT]: buildPaymentState({ diff --git a/libs/application/templates/transport-authority/license-plate-renewal/src/utils/index.ts b/libs/application/templates/transport-authority/license-plate-renewal/src/utils/index.ts index 03b0941c3e54..69aa4fbeac9d 100644 --- a/libs/application/templates/transport-authority/license-plate-renewal/src/utils/index.ts +++ b/libs/application/templates/transport-authority/license-plate-renewal/src/utils/index.ts @@ -1,20 +1,13 @@ import { LicensePlateRenewal } from '../lib/dataSchema' import { ChargeItemCode } from '@island.is/shared/constants' import { Application, ExtraData } from '@island.is/application/types' - -export const getChargeItemCodeWithAnswers = ( - answers: LicensePlateRenewal, -): Array => { - const result = [ - ChargeItemCode.TRANSPORT_AUTHORITY_LICENSE_PLATE_RENEWAL.toString(), - ] - - return result -} +import { isPaymentRequired } from './isPaymentRequired' export const getChargeItemCodes = (application: Application): Array => { - const answers = application.answers as LicensePlateRenewal - return getChargeItemCodeWithAnswers(answers) + const paymentRequired = isPaymentRequired({ application }) + return paymentRequired + ? [ChargeItemCode.TRANSPORT_AUTHORITY_LICENSE_PLATE_RENEWAL.toString()] + : [] } export const getExtraData = (application: Application): ExtraData[] => { diff --git a/libs/application/templates/transport-authority/license-plate-renewal/src/utils/isPaymentRequired.ts b/libs/application/templates/transport-authority/license-plate-renewal/src/utils/isPaymentRequired.ts new file mode 100644 index 000000000000..4383d49d35b0 --- /dev/null +++ b/libs/application/templates/transport-authority/license-plate-renewal/src/utils/isPaymentRequired.ts @@ -0,0 +1,17 @@ +import { getValueViaPath } from '@island.is/application/core' +import { ApplicationContext } from '@island.is/application/types' +import { info } from 'kennitala' + +export const isPaymentRequired = ({ application }: ApplicationContext) => { + const nationalId = getValueViaPath( + application.externalData, + 'identity.data.nationalId', + '', + ) as string + if (!nationalId) { + return true + } + + const age = info(nationalId).age + return age < 65 +} From 5f6d92d27517c69f4ed7cb972f84dc70ff327958 Mon Sep 17 00:00:00 2001 From: kksteini <77672665+kksteini@users.noreply.github.com> Date: Thu, 30 May 2024 11:33:04 +0000 Subject: [PATCH 16/82] fix(application-ir): Minor parameter fix (#15014) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../templates/inheritance-report/inheritance-report.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts index bc0e5a2811ee..9b73084d4509 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts @@ -68,7 +68,7 @@ export class InheritanceReportService extends BaseTemplateApiService { return new Promise((resolve) => { this.syslumennService - .getInheritanceTax(new Date()) + .getInheritanceTax(inheritanceDate) .then((inheritanceTax) => { inheritanceReportInfo.inheritanceTax = inheritanceTax resolve() From 9591f960ffdfeb6586e88d283a0317669f3ff097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Thu, 30 May 2024 11:56:42 +0000 Subject: [PATCH 17/82] fix(documents): Remove type check. Add content detection (#15012) * Remove type check. Add content detection * chore: nx format:write update dirty files --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: andes-it --- .../documents/src/lib/documentV2.service.ts | 2 +- .../documents-v2/src/lib/dto/document.dto.ts | 46 +++++-------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/libs/api/domains/documents/src/lib/documentV2.service.ts b/libs/api/domains/documents/src/lib/documentV2.service.ts index 7ee342a638f4..90a2900a7670 100644 --- a/libs/api/domains/documents/src/lib/documentV2.service.ts +++ b/libs/api/domains/documents/src/lib/documentV2.service.ts @@ -45,7 +45,7 @@ export class DocumentServiceV2 { } if (!document) { - this.logger.error('No document content', { + this.logger.warn('No document content', { category: LOG_CATEGORY, documentId, }) diff --git a/libs/clients/documents-v2/src/lib/dto/document.dto.ts b/libs/clients/documents-v2/src/lib/dto/document.dto.ts index baa9dbd86901..573b3bfbb14d 100644 --- a/libs/clients/documents-v2/src/lib/dto/document.dto.ts +++ b/libs/clients/documents-v2/src/lib/dto/document.dto.ts @@ -17,41 +17,17 @@ export type DocumentDto = { export const mapToDocument = (document: DocumentDTO): DocumentDto | null => { let fileType: FileType, content: string - switch (document.fileType) { - case 'pdf': - if (!document.content) { - return null - } - fileType = 'pdf' - content = document.content - break - case 'html': - if (!document.htmlContent) { - return null - } - fileType = 'html' - content = document.htmlContent - break - case 'url': - if (!document.url) { - return null - } - fileType = 'url' - content = document.url - break - default: - // Some document providers can not explicitly set the fileType so we have to guess the fileType by checking for the content, in case the fileType is not set. - if (document.htmlContent) { - fileType = 'html' - content = document.htmlContent - break - } - if (document.url) { - fileType = 'url' - content = document.url - break - } - return null + if (document.content) { + fileType = 'pdf' + content = document.content + } else if (document.url) { + fileType = 'url' + content = document.url + } else if (document.htmlContent) { + fileType = 'html' + content = document.htmlContent + } else { + return null } return { From f4107cc2d8505a16c236ef07738d6ad791dc8d75 Mon Sep 17 00:00:00 2001 From: lommi Date: Thu, 30 May 2024 12:22:07 +0000 Subject: [PATCH 18/82] fix: build (#15015) * fix: build * chore: nx format:write update dirty files * fix: build * chore: nx format:write update dirty files --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .github/actions/change-detection.ts | 206 +++++++++++++++------------- .github/actions/dist/main.js | 197 +++++++++++++------------- .github/actions/main.ts | 3 +- 3 files changed, 217 insertions(+), 189 deletions(-) diff --git a/.github/actions/change-detection.ts b/.github/actions/change-detection.ts index 5f15fea66944..80dc85092e4b 100644 --- a/.github/actions/change-detection.ts +++ b/.github/actions/change-detection.ts @@ -29,36 +29,43 @@ export async function findBestGoodRefBranch( baseBranch: string, workflowId: WorkflowID, ): Promise { - const log = app.extend('findBestGoodRefBranch') - log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`) - const commits = await getCommits(git, headBranch, baseBranch, 'HEAD~1') - const builds = await githubApi.getLastGoodBranchBuildRun( - headBranch, - workflowId, - commits, - ) - if (builds) - return { - sha: builds.head_commit, - run_number: builds.run_nr, - branch: headBranch, - ref: builds.head_commit, + return new Promise(async (resolve) => { + const log = app.extend('findBestGoodRefBranch') + log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`) + const commits = await getCommits(git, headBranch, baseBranch, 'HEAD~1') + const builds = await githubApi.getLastGoodBranchBuildRun( + headBranch, + workflowId, + commits, + ) + if (builds) { + resolve({ + sha: builds.head_commit, + run_number: builds.run_nr, + branch: headBranch, + ref: builds.head_commit, + }) + return } - const baseCommits = await githubApi.getLastGoodBranchBuildRun( - baseBranch, - workflowId, - commits, - ) - if (baseCommits) - return { - ref: baseCommits.head_commit, - sha: baseCommits.head_commit, - run_number: baseCommits.run_nr, - branch: baseBranch, + const baseCommits = await githubApi.getLastGoodBranchBuildRun( + baseBranch, + workflowId, + commits, + ) + if (baseCommits) { + resolve({ + ref: baseCommits.head_commit, + sha: baseCommits.head_commit, + run_number: baseCommits.run_nr, + branch: baseBranch, + }) + return } - return 'rebuild' + resolve('rebuild') + return + }) } /*** @@ -111,82 +118,89 @@ export async function findBestGoodRefPR( prBranch: string, workflowId: WorkflowID, ): Promise { - const log = app.extend('findBestGoodRefPR') - log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`) - const lastCommitSha = await git.lastCommit() - const prCommits = await getCommits(git, headBranch, baseBranch, 'HEAD') + return new Promise(async (resolve) => { + const log = app.extend('findBestGoodRefPR') + log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`) + const lastCommitSha = await git.lastCommit() + const prCommits = await getCommits(git, headBranch, baseBranch, 'HEAD') - const prRun = await githubApi.getLastGoodPRRun( - headBranch, - workflowId, - prCommits, - ) - const prBuilds: { - distance: number - hash: string - run_nr: number - branch: string - ref: string - }[] = [] - if (prRun) { - log(`Found a PR run candidate: ${JSON.stringify(prRun)}`) - try { - const tempBranch = `${headBranch}-${Math.round(Math.random() * 1000000)}` - await git.checkoutBranch(tempBranch, prRun.base_commit) - log(`Branch checked out`) - const mergeCommitSha = await git.merge(prRun.head_commit) - log(`Simulated previous PR merge commit`) - const distance = await githubApi.getChangedComponents( + const prRun = await githubApi.getLastGoodPRRun( + headBranch, + workflowId, + prCommits, + ) + const prBuilds: { + distance: number + hash: string + run_nr: number + branch: string + ref: string + }[] = [] + if (prRun) { + log(`Found a PR run candidate: ${JSON.stringify(prRun)}`) + try { + const tempBranch = `${headBranch}-${Math.round( + Math.random() * 1000000, + )}` + await git.checkoutBranch(tempBranch, prRun.base_commit) + log(`Branch checked out`) + const mergeCommitSha = await git.merge(prRun.head_commit) + log(`Simulated previous PR merge commit`) + const distance = await githubApi.getChangedComponents( + git, + lastCommitSha, + mergeCommitSha, + ) + log(`Affected components since candidate PR run are ${distance}`) + prBuilds.push({ + distance: diffWeight(distance), + hash: prRun.head_commit, + run_nr: prRun.run_nr, + branch: headBranch, + ref: mergeCommitSha, + }) + } catch (e) { + log( + `Error processing PR candidate(${prRun.run_nr}) but continuing: %O`, + e, + ) + } finally { + await git.checkout(prBranch) + } + } + + const baseCommits = await getCommits(git, prBranch, baseBranch, 'HEAD~1') + + const baseGoodBuilds = await githubApi.getLastGoodBranchBuildRun( + baseBranch, + 'push', + baseCommits, + ) + if (baseGoodBuilds) { + let affectedComponents = await githubApi.getChangedComponents( git, lastCommitSha, - mergeCommitSha, + baseGoodBuilds.head_commit, ) - log(`Affected components since candidate PR run are ${distance}`) prBuilds.push({ - distance: diffWeight(distance), - hash: prRun.head_commit, - run_nr: prRun.run_nr, - branch: headBranch, - ref: mergeCommitSha, + distance: diffWeight(affectedComponents), + hash: baseGoodBuilds.head_commit, + run_nr: baseGoodBuilds.run_nr, + branch: baseBranch, + ref: baseGoodBuilds.head_commit, }) - } catch (e) { - log( - `Error processing PR candidate(${prRun.run_nr}) but continuing: %O`, - e, - ) - } finally { - await git.checkout(prBranch) } - } - - const baseCommits = await getCommits(git, prBranch, baseBranch, 'HEAD~1') - - const baseGoodBuilds = await githubApi.getLastGoodBranchBuildRun( - baseBranch, - 'push', - baseCommits, - ) - if (baseGoodBuilds) { - let affectedComponents = await githubApi.getChangedComponents( - git, - lastCommitSha, - baseGoodBuilds.head_commit, - ) - prBuilds.push({ - distance: diffWeight(affectedComponents), - hash: baseGoodBuilds.head_commit, - run_nr: baseGoodBuilds.run_nr, - branch: baseBranch, - ref: baseGoodBuilds.head_commit, - }) - } - prBuilds.sort((a, b) => (a.distance > b.distance ? 1 : -1)) - if (prBuilds.length > 0) - return { - sha: prBuilds[0].hash, - run_number: prBuilds[0].run_nr, - branch: prBuilds[0].branch.replace('origin/', ''), - ref: prBuilds[0].ref, + prBuilds.sort((a, b) => (a.distance > b.distance ? 1 : -1)) + if (prBuilds.length > 0) { + resolve({ + sha: prBuilds[0].hash, + run_number: prBuilds[0].run_nr, + branch: prBuilds[0].branch.replace('origin/', ''), + ref: prBuilds[0].ref, + }) + return } - return 'rebuild' + resolve('rebuild') + return + }) } diff --git a/.github/actions/dist/main.js b/.github/actions/dist/main.js index fb9ddace8f2a..7069298320f8 100644 --- a/.github/actions/dist/main.js +++ b/.github/actions/dist/main.js @@ -26107,34 +26107,41 @@ var import_debug2 = __toESM(require_src()); var app2 = (0, import_debug2.default)("change-detection"); function findBestGoodRefBranch(commitScore, git, githubApi, headBranch, baseBranch, workflowId) { return __async(this, null, function* () { - const log = app2.extend("findBestGoodRefBranch"); - log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`); - const commits = yield getCommits(git, headBranch, baseBranch, "HEAD~1"); - const builds = yield githubApi.getLastGoodBranchBuildRun( - headBranch, - workflowId, - commits - ); - if (builds) - return { - sha: builds.head_commit, - run_number: builds.run_nr, - branch: headBranch, - ref: builds.head_commit - }; - const baseCommits = yield githubApi.getLastGoodBranchBuildRun( - baseBranch, - workflowId, - commits - ); - if (baseCommits) - return { - ref: baseCommits.head_commit, - sha: baseCommits.head_commit, - run_number: baseCommits.run_nr, - branch: baseBranch - }; - return "rebuild"; + return new Promise((resolve) => __async(this, null, function* () { + const log = app2.extend("findBestGoodRefBranch"); + log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`); + const commits = yield getCommits(git, headBranch, baseBranch, "HEAD~1"); + const builds = yield githubApi.getLastGoodBranchBuildRun( + headBranch, + workflowId, + commits + ); + if (builds) { + resolve({ + sha: builds.head_commit, + run_number: builds.run_nr, + branch: headBranch, + ref: builds.head_commit + }); + return; + } + const baseCommits = yield githubApi.getLastGoodBranchBuildRun( + baseBranch, + workflowId, + commits + ); + if (baseCommits) { + resolve({ + ref: baseCommits.head_commit, + sha: baseCommits.head_commit, + run_number: baseCommits.run_nr, + branch: baseBranch + }); + return; + } + resolve("rebuild"); + return; + })); }); } function getCommits(git, headBranch, baseBranch, head, maxCount = 300) { @@ -26152,75 +26159,80 @@ function getCommits(git, headBranch, baseBranch, head, maxCount = 300) { } function findBestGoodRefPR(diffWeight, git, githubApi, headBranch, baseBranch, prBranch, workflowId) { return __async(this, null, function* () { - const log = app2.extend("findBestGoodRefPR"); - log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`); - const lastCommitSha = yield git.lastCommit(); - const prCommits = yield getCommits(git, headBranch, baseBranch, "HEAD"); - const prRun = yield githubApi.getLastGoodPRRun( - headBranch, - workflowId, - prCommits - ); - const prBuilds = []; - if (prRun) { - log(`Found a PR run candidate: ${JSON.stringify(prRun)}`); - try { - const tempBranch = `${headBranch}-${Math.round(Math.random() * 1e6)}`; - yield git.checkoutBranch(tempBranch, prRun.base_commit); - log(`Branch checked out`); - const mergeCommitSha = yield git.merge(prRun.head_commit); - log(`Simulated previous PR merge commit`); - const distance = yield githubApi.getChangedComponents( + return new Promise((resolve) => __async(this, null, function* () { + const log = app2.extend("findBestGoodRefPR"); + log(`Starting with head branch ${headBranch} and base branch ${baseBranch}`); + const lastCommitSha = yield git.lastCommit(); + const prCommits = yield getCommits(git, headBranch, baseBranch, "HEAD"); + const prRun = yield githubApi.getLastGoodPRRun( + headBranch, + workflowId, + prCommits + ); + const prBuilds = []; + if (prRun) { + log(`Found a PR run candidate: ${JSON.stringify(prRun)}`); + try { + const tempBranch = `${headBranch}-${Math.round(Math.random() * 1e6)}`; + yield git.checkoutBranch(tempBranch, prRun.base_commit); + log(`Branch checked out`); + const mergeCommitSha = yield git.merge(prRun.head_commit); + log(`Simulated previous PR merge commit`); + const distance = yield githubApi.getChangedComponents( + git, + lastCommitSha, + mergeCommitSha + ); + log(`Affected components since candidate PR run are ${distance}`); + prBuilds.push({ + distance: diffWeight(distance), + hash: prRun.head_commit, + run_nr: prRun.run_nr, + branch: headBranch, + ref: mergeCommitSha + }); + } catch (e) { + log( + `Error processing PR candidate(${prRun.run_nr}) but continuing: %O`, + e + ); + } finally { + yield git.checkout(prBranch); + } + } + const baseCommits = yield getCommits(git, prBranch, baseBranch, "HEAD~1"); + const baseGoodBuilds = yield githubApi.getLastGoodBranchBuildRun( + baseBranch, + "push", + baseCommits + ); + if (baseGoodBuilds) { + let affectedComponents = yield githubApi.getChangedComponents( git, lastCommitSha, - mergeCommitSha + baseGoodBuilds.head_commit ); - log(`Affected components since candidate PR run are ${distance}`); prBuilds.push({ - distance: diffWeight(distance), - hash: prRun.head_commit, - run_nr: prRun.run_nr, - branch: headBranch, - ref: mergeCommitSha + distance: diffWeight(affectedComponents), + hash: baseGoodBuilds.head_commit, + run_nr: baseGoodBuilds.run_nr, + branch: baseBranch, + ref: baseGoodBuilds.head_commit }); - } catch (e) { - log( - `Error processing PR candidate(${prRun.run_nr}) but continuing: %O`, - e - ); - } finally { - yield git.checkout(prBranch); } - } - const baseCommits = yield getCommits(git, prBranch, baseBranch, "HEAD~1"); - const baseGoodBuilds = yield githubApi.getLastGoodBranchBuildRun( - baseBranch, - "push", - baseCommits - ); - if (baseGoodBuilds) { - let affectedComponents = yield githubApi.getChangedComponents( - git, - lastCommitSha, - baseGoodBuilds.head_commit - ); - prBuilds.push({ - distance: diffWeight(affectedComponents), - hash: baseGoodBuilds.head_commit, - run_nr: baseGoodBuilds.run_nr, - branch: baseBranch, - ref: baseGoodBuilds.head_commit - }); - } - prBuilds.sort((a, b) => a.distance > b.distance ? 1 : -1); - if (prBuilds.length > 0) - return { - sha: prBuilds[0].hash, - run_number: prBuilds[0].run_nr, - branch: prBuilds[0].branch.replace("origin/", ""), - ref: prBuilds[0].ref - }; - return "rebuild"; + prBuilds.sort((a, b) => a.distance > b.distance ? 1 : -1); + if (prBuilds.length > 0) { + resolve({ + sha: prBuilds[0].hash, + run_number: prBuilds[0].run_nr, + branch: prBuilds[0].branch.replace("origin/", ""), + ref: prBuilds[0].ref + }); + return; + } + resolve("rebuild"); + return; + })); }); } @@ -26345,11 +26357,12 @@ var FULL_REBUILD_NEEDED = "full_rebuild_needed"; ); if (rev === "rebuild") { console.log(FULL_REBUILD_NEEDED); - return; + process.exit(0); } rev.branch = rev.branch.replace(/'/g, ""); rev.ref = rev.ref.replace(/'/g, ""); console.log(JSON.stringify(rev)); + process.exit(0); }))(); /*! * is-plain-object diff --git a/.github/actions/main.ts b/.github/actions/main.ts index 3deb43ad0586..75872b21f061 100644 --- a/.github/actions/main.ts +++ b/.github/actions/main.ts @@ -37,9 +37,10 @@ const FULL_REBUILD_NEEDED = 'full_rebuild_needed' if (rev === 'rebuild') { console.log(FULL_REBUILD_NEEDED) - return + process.exit(0) } rev.branch = rev.branch.replace(/'/g, '') rev.ref = rev.ref.replace(/'/g, '') console.log(JSON.stringify(rev)) + process.exit(0) })() From 2ffbc9776f9a391919492bb109640469a703f0d4 Mon Sep 17 00:00:00 2001 From: davidkef <52493597+davidkef@users.noreply.github.com> Date: Thu, 30 May 2024 12:48:33 +0000 Subject: [PATCH 19/82] fix(SGS): Fixed order plate of unknown type (#14970) * Inital commit * Adding error message for no matching plate sgs * adding optional chaining operator back in plate size component --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/fields/PickPlateSize.tsx | 10 ++++++++-- .../src/lib/messages/information.ts | 6 ++++++ .../src/lib/vehicleCodetablesClient.service.ts | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/application/templates/transport-authority/order-vehicle-license-plate/src/fields/PickPlateSize.tsx b/libs/application/templates/transport-authority/order-vehicle-license-plate/src/fields/PickPlateSize.tsx index 78390521220f..d29a97fcb2e6 100644 --- a/libs/application/templates/transport-authority/order-vehicle-license-plate/src/fields/PickPlateSize.tsx +++ b/libs/application/templates/transport-authority/order-vehicle-license-plate/src/fields/PickPlateSize.tsx @@ -54,6 +54,10 @@ export const PickPlateSize: FC> = ( // Plate type front should always be defined (rear type can be empty in some cases) const plateTypeFrontError = !currentPlateTypeFront + const noPlateMatchError = + plateTypeList?.filter((x) => x.code === currentPlateTypeFront)?.length === + 0 ?? false + useEffect(() => { if (!loading && currentPlateTypeRear === null) { setValue(`${props.field.id}.rearPlateSize`, []) @@ -73,7 +77,7 @@ export const PickPlateSize: FC> = ( repeat={2} borderRadius="large" /> - ) : !error && !plateTypeFrontError ? ( + ) : !error && !plateTypeFrontError && !noPlateMatchError ? ( <> {formatMessage(information.labels.plateSize.frontPlateSubtitle)} @@ -133,7 +137,9 @@ export const PickPlateSize: FC> = ( { - const result = await this.codetablesApi.platetypesAllGet({ + const result = await this.codetablesApi.platetypesGet({ apiVersion: '2.0', apiVersion2: '2.0', }) From 5452a2c4957a74d00c6821c8538146fb1cb4a28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Thu, 30 May 2024 13:28:55 +0000 Subject: [PATCH 20/82] feat(j-s): Indictment dismissal and cancelation (#14984) * Adds dismissal and cancelation as possible indictment completions * Fixes broken tags * Changes spelling * Fixes step validation og unit tests --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../case-list/models/caseList.model.ts | 4 + .../case/interceptors/caseList.interceptor.ts | 1 + .../Table/PastCasesTable/MobilePastCase.tsx | 1 + .../Table/PastCasesTable/PastCasesTable.tsx | 1 + .../TagCaseState/TagCaseState.spec.ts | 2 +- .../TagCaseState/TagCaseState.strings.ts | 6 + .../components/TagCaseState/TagCaseState.tsx | 18 +- .../Conclusion/Conclusion.strings.ts | 18 ++ .../Indictments/Conclusion/Conclusion.tsx | 156 +++++++++++++----- .../Cases/components/DefenderCasesTable.tsx | 1 + .../Tables/CasesForReview.tsx | 1 + .../src/routes/Shared/Cases/ActiveCases.tsx | 1 + .../src/routes/Shared/Cases/MobileCase.tsx | 1 + .../web/src/routes/Shared/Cases/cases.graphql | 1 + .../web/src/utils/formHelper.ts | 12 +- .../judicial-system/web/src/utils/validate.ts | 5 + .../formatters/src/lib/formatters.ts | 8 +- libs/judicial-system/types/src/lib/case.ts | 2 + 18 files changed, 180 insertions(+), 59 deletions(-) diff --git a/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts b/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts index fda810ed9962..e087ad955c7f 100644 --- a/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts +++ b/apps/judicial-system/api/src/app/modules/case-list/models/caseList.model.ts @@ -5,6 +5,7 @@ import { CaseAppealRulingDecision, CaseAppealState, CaseDecision, + CaseIndictmentRulingDecision, CaseState, CaseType, IndictmentCaseReviewDecision, @@ -120,4 +121,7 @@ export class CaseListEntry { @Field(() => String, { nullable: true }) readonly indictmentVerdictAppealDeadline?: string + + @Field(() => CaseIndictmentRulingDecision, { nullable: true }) + readonly indictmentRulingDecision?: CaseIndictmentRulingDecision } diff --git a/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts index af0efc03b223..940d763221d6 100644 --- a/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts +++ b/apps/judicial-system/backend/src/app/modules/case/interceptors/caseList.interceptor.ts @@ -58,6 +58,7 @@ export class CaseListInterceptor implements NestInterceptor { )?.comment, indictmentReviewer: theCase.indictmentReviewer, indictmentReviewDecision: theCase.indictmentReviewDecision, + indictmentRulingDecision: theCase.indictmentRulingDecision, } }), ), diff --git a/apps/judicial-system/web/src/components/Table/PastCasesTable/MobilePastCase.tsx b/apps/judicial-system/web/src/components/Table/PastCasesTable/MobilePastCase.tsx index 3879a63f7bc0..e15880b458b2 100644 --- a/apps/judicial-system/web/src/components/Table/PastCasesTable/MobilePastCase.tsx +++ b/apps/judicial-system/web/src/components/Table/PastCasesTable/MobilePastCase.tsx @@ -43,6 +43,7 @@ const MobilePastCase: React.FC = ({ isCourtRole={isCourtRole} isValidToDateInThePast={theCase.isValidToDateInThePast} courtDate={theCase.courtDate} + indictmentRulingDecision={theCase.indictmentRulingDecision} />, ]} isLoading={isLoading} diff --git a/apps/judicial-system/web/src/components/Table/PastCasesTable/PastCasesTable.tsx b/apps/judicial-system/web/src/components/Table/PastCasesTable/PastCasesTable.tsx index c7db3878682b..64595d53231a 100644 --- a/apps/judicial-system/web/src/components/Table/PastCasesTable/PastCasesTable.tsx +++ b/apps/judicial-system/web/src/components/Table/PastCasesTable/PastCasesTable.tsx @@ -169,6 +169,7 @@ const PastCasesTable: React.FC> = (props) => { caseType={column.type} isCourtRole={isDistrictCourtUser(user)} isValidToDateInThePast={column.isValidToDateInThePast} + indictmentRulingDecision={column.indictmentRulingDecision} /> {column.appealState && ( diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts index 2dce52f5335b..d742df360bc2 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.spec.ts @@ -78,7 +78,7 @@ describe('mapCaseStateToTagVariant', () => { text: strings.active.defaultMessage, }) - expect(fn(CaseState.ACCEPTED, false, CaseType.INDICTMENT)).toEqual({ + expect(fn(CaseState.COMPLETED, false, CaseType.INDICTMENT)).toEqual({ color: 'darkerBlue', text: strings.inactive.defaultMessage, }) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts index 2bcb77190931..23440548181d 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.strings.ts @@ -67,4 +67,10 @@ export const strings = defineMessages({ defaultMessage: 'Móttekið', description: 'Notað sem merki þegar mál í stöðu "Móttekið" í málalista', }, + completed: { + id: 'judicial.system.core:tag_case_state.completed', + defaultMessage: + '{indictmentRulingDecision, select, RULING {Dómur} FINE {Viðurlagaákvörðun} DISMISSAL {Frávísun} CANCELLATION {Niðurfelling} other {Lokið}}', + description: 'Notað sem merki þegar mál í stöðu "Dómþulur" í málalista', + }, }) diff --git a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx index e920234c4642..8cb3498d30bc 100644 --- a/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx +++ b/apps/judicial-system/web/src/components/TagCaseState/TagCaseState.tsx @@ -2,11 +2,9 @@ import React from 'react' import { IntlShape, useIntl } from 'react-intl' import { Tag, TagVariant } from '@island.is/island-ui/core' +import { isInvestigationCase } from '@island.is/judicial-system/types' import { - isIndictmentCase, - isInvestigationCase, -} from '@island.is/judicial-system/types' -import { + CaseIndictmentRulingDecision, CaseState, CaseType, User, @@ -21,6 +19,7 @@ interface Props { isValidToDateInThePast?: boolean | null courtDate?: string | null indictmentReviewer?: User | null + indictmentRulingDecision?: CaseIndictmentRulingDecision | null customMapCaseStateToTag?: ( formatMessage: IntlShape['formatMessage'], state?: CaseState | null, @@ -53,6 +52,7 @@ export const mapCaseStateToTagVariant = ( isValidToDateInThePast?: boolean | null, scheduledDate?: string | null, isCourtRole?: boolean, + indictmentRulingDecision?: CaseIndictmentRulingDecision | null, ): { color: TagVariant; text: string } => { switch (state) { case CaseState.NEW: @@ -71,8 +71,7 @@ export const mapCaseStateToTagVariant = ( case CaseState.MAIN_HEARING: return { color: 'blue', text: formatMessage(strings.reassignment) } case CaseState.ACCEPTED: - case CaseState.COMPLETED: - return isIndictmentCase(caseType) || isValidToDateInThePast + return isValidToDateInThePast ? { color: 'darkerBlue', text: formatMessage(strings.inactive) } : { color: 'blue', @@ -84,6 +83,11 @@ export const mapCaseStateToTagVariant = ( return { color: 'rose', text: formatMessage(strings.rejected) } case CaseState.DISMISSED: return { color: 'dark', text: formatMessage(strings.dismissed) } + case CaseState.COMPLETED: + return { + color: 'darkerBlue', + text: formatMessage(strings.completed, { indictmentRulingDecision }), + } default: return { color: 'white', text: formatMessage(strings.unknown) } } @@ -98,6 +102,7 @@ const TagCaseState: React.FC> = (Props) => { isValidToDateInThePast, courtDate, indictmentReviewer, + indictmentRulingDecision, customMapCaseStateToTag, } = Props @@ -110,6 +115,7 @@ const TagCaseState: React.FC> = (Props) => { isValidToDateInThePast, courtDate, isCourtRole, + indictmentRulingDecision, ) if (!tagVariant) return null diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts index 754da4c18635..27e2e7de5f97 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.strings.ts @@ -85,10 +85,28 @@ export const strings = defineMessages({ description: 'Notaður sem fyrirsögn fyrir Dómur upphlöðunarsvæði á Niðurstaða skrefi.', }, + dismissalUploadTitle: { + id: 'judicial.system.core:court.indictments.conclusion.dismissal_upload_title', + defaultMessage: 'Úrskurður', + description: + 'Notaður sem fyrirsögn fyrir Úrskurður upphlöðunarsvæði á Niðurstaða skrefi.', + }, fine: { id: 'judicial.system.core:court.indictments.conclusion.fine', defaultMessage: 'Viðurlagaákvörðun', description: 'Notaður sem texti í viðurlagaákvörðun valmöguleika á Niðurstaða skrefi.', }, + dismissal: { + id: 'judicial.system.core:court.indictments.conclusion.dismissal', + defaultMessage: 'Frávísun', + description: + 'Notaður sem texti í frávísun valmöguleika á Niðurstaða skrefi.', + }, + cancellation: { + id: 'judicial.system.core:court.indictments.conclusion.cancellation', + defaultMessage: 'Niðurfelling máls', + description: + 'Notaður sem texti í niðurfelling máls valmöguleika á Niðurstaða skrefi.', + }, }) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx index 02feab53e48a..efaf2cb02a8b 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Conclusion/Conclusion.tsx @@ -41,8 +41,10 @@ import { strings } from './Conclusion.strings' type Actions = 'POSTPONE' | 'REDISTRIBUTE' | 'COMPLETE' type Decision = - | CaseIndictmentRulingDecision.FINE | CaseIndictmentRulingDecision.RULING + | CaseIndictmentRulingDecision.FINE + | CaseIndictmentRulingDecision.DISMISSAL + | CaseIndictmentRulingDecision.CANCELLATION interface Postponement { postponedIndefinitely?: boolean @@ -165,24 +167,51 @@ const Conclusion: React.FC = () => { ]) const stepIsValid = () => { - if (!selectedAction) { + if (!allFilesDoneOrError) { return false } - if (selectedAction === 'REDISTRIBUTE') { - return uploadFiles.find( - (file) => file.category === CaseFileCategory.COURT_RECORD, - ) - } else if (selectedAction === 'POSTPONE') { - return ( - Boolean( + switch (selectedAction) { + case 'POSTPONE': + return Boolean( postponement?.postponedIndefinitely ? postponement.reason : courtDate?.date, - ) && allFilesDoneOrError - ) - } else if (selectedAction === 'COMPLETE') { - return selectedDecision !== undefined && allFilesDoneOrError + ) + case 'REDISTRIBUTE': + return uploadFiles.some( + (file) => + file.category === CaseFileCategory.COURT_RECORD && + file.status === 'done', + ) + case 'COMPLETE': + switch (selectedDecision) { + case CaseIndictmentRulingDecision.RULING: + case CaseIndictmentRulingDecision.DISMISSAL: + return ( + uploadFiles.some( + (file) => + file.category === CaseFileCategory.COURT_RECORD && + file.status === 'done', + ) && + uploadFiles.some( + (file) => + file.category === CaseFileCategory.RULING && + file.status === 'done', + ) + ) + case CaseIndictmentRulingDecision.FINE: + case CaseIndictmentRulingDecision.CANCELLATION: + return uploadFiles.some( + (file) => + file.category === CaseFileCategory.COURT_RECORD && + file.status === 'done', + ) + default: + return false + } + default: + return false } } @@ -191,7 +220,7 @@ const Conclusion: React.FC = () => { workingCase={workingCase} isLoading={isLoadingWorkingCase} notFound={caseNotFound} - isValid={allFilesDoneOrError} + isValid={stepIsValid()} onNavigationTo={handleNavigationTo} > @@ -317,16 +346,48 @@ const Conclusion: React.FC = () => { label={formatMessage(strings.ruling)} /> + + { + setSelectedDecision(CaseIndictmentRulingDecision.FINE) + }} + large + backgroundColor="white" + label={formatMessage(strings.fine)} + /> + + + { + setSelectedDecision(CaseIndictmentRulingDecision.DISMISSAL) + }} + large + backgroundColor="white" + label={formatMessage(strings.dismissal)} + /> + { - setSelectedDecision(CaseIndictmentRulingDecision.FINE) + setSelectedDecision(CaseIndictmentRulingDecision.CANCELLATION) }} large backgroundColor="white" - label={formatMessage(strings.fine)} + label={formatMessage(strings.cancellation)} /> @@ -335,7 +396,7 @@ const Conclusion: React.FC = () => { { /> )} - {selectedDecision === 'RULING' && ( - - - file.category === CaseFileCategory.RULING, - )} - accept="application/pdf" - header={formatMessage(strings.inputFieldLabel)} - description={formatMessage(core.uploadBoxDescription, { - fileEndings: '.pdf', - })} - buttonLabel={formatMessage(strings.uploadButtonText)} - onChange={(files) => { - handleUpload( - addUploadFiles(files, CaseFileCategory.RULING), - updateUploadFile, - ) - }} - onRemove={(file) => handleRemove(file, removeUploadFile)} - onRetry={(file) => handleRetry(file, updateUploadFile)} - /> - - )} + {selectedAction === 'COMPLETE' && + (selectedDecision === CaseIndictmentRulingDecision.RULING || + selectedDecision === CaseIndictmentRulingDecision.DISMISSAL) && ( + + + file.category === CaseFileCategory.RULING, + )} + accept="application/pdf" + header={formatMessage(strings.inputFieldLabel)} + description={formatMessage(core.uploadBoxDescription, { + fileEndings: '.pdf', + })} + buttonLabel={formatMessage(strings.uploadButtonText)} + onChange={(files) => { + handleUpload( + addUploadFiles(files, CaseFileCategory.RULING), + updateUploadFile, + ) + }} + onRemove={(file) => handleRemove(file, removeUploadFile)} + onRetry={(file) => handleRetry(file, updateUploadFile)} + /> + + )} > = ( caseType={column.type} isValidToDateInThePast={column.isValidToDateInThePast} courtDate={column.courtDate} + indictmentRulingDecision={column.indictmentRulingDecision} /> {column.appealState && ( diff --git a/apps/judicial-system/web/src/routes/PublicProsecutor/Tables/CasesForReview.tsx b/apps/judicial-system/web/src/routes/PublicProsecutor/Tables/CasesForReview.tsx index 197b5222d399..ac8a40e59f23 100644 --- a/apps/judicial-system/web/src/routes/PublicProsecutor/Tables/CasesForReview.tsx +++ b/apps/judicial-system/web/src/routes/PublicProsecutor/Tables/CasesForReview.tsx @@ -80,6 +80,7 @@ const CasesForReview: React.FC = ({ mapIndictmentCaseStateToTagVariant } indictmentReviewer={row.indictmentReviewer} + indictmentRulingDecision={row.indictmentRulingDecision} /> ), }, diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx index 1c52098aa36d..9669f6d46f5f 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/ActiveCases.tsx @@ -326,6 +326,7 @@ const ActiveCases: React.FC> = (props) => { isCourtRole={isDistrictCourtUser(user)} isValidToDateInThePast={c.isValidToDateInThePast} courtDate={c.courtDate} + indictmentRulingDecision={c.indictmentRulingDecision} /> {c.appealState && ( diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/MobileCase.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/MobileCase.tsx index fe5104b2d64d..7ebc39545481 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/MobileCase.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/MobileCase.tsx @@ -78,6 +78,7 @@ const MobileCase: React.FC> = ({ isCourtRole={isCourtRole} isValidToDateInThePast={theCase.isValidToDateInThePast} courtDate={theCase.courtDate} + indictmentRulingDecision={theCase.indictmentRulingDecision} />, ]} isLoading={isLoading} diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql index 2fd62e99ff51..a60971d44f0e 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql @@ -92,5 +92,6 @@ query Cases { indictmentAppealDeadline indictmentVerdictViewedByAll indictmentVerdictAppealDeadline + indictmentRulingDecision } } diff --git a/apps/judicial-system/web/src/utils/formHelper.ts b/apps/judicial-system/web/src/utils/formHelper.ts index bc47dc522288..8cc151880683 100644 --- a/apps/judicial-system/web/src/utils/formHelper.ts +++ b/apps/judicial-system/web/src/utils/formHelper.ts @@ -190,7 +190,7 @@ export type stepValidationsType = { ) => boolean [constants.INDICTMENTS_SUBPOENA_ROUTE]: (theCase: Case) => boolean [constants.INDICTMENTS_DEFENDER_ROUTE]: (theCase: Case) => boolean - [constants.INDICTMENTS_CONCLUSION_ROUTE]: () => boolean + [constants.INDICTMENTS_CONCLUSION_ROUTE]: (theCase: Case) => boolean [constants.INDICTMENTS_COURT_OVERVIEW_ROUTE]: () => boolean [constants.INDICTMENTS_SUMMARY_ROUTE]: () => boolean [constants.COURT_OF_APPEAL_OVERVIEW_ROUTE]: () => boolean @@ -279,7 +279,8 @@ export const stepValidations = (): stepValidationsType => { validations.isSubpoenaStepValid(theCase), [constants.INDICTMENTS_DEFENDER_ROUTE]: (theCase: Case) => validations.isDefenderStepValid(theCase), - [constants.INDICTMENTS_CONCLUSION_ROUTE]: () => true, + [constants.INDICTMENTS_CONCLUSION_ROUTE]: (theCase: Case) => + validations.isConclusionStepValid(theCase), [constants.INDICTMENTS_COURT_OVERVIEW_ROUTE]: () => true, [constants.COURT_OF_APPEAL_OVERVIEW_ROUTE]: () => true, [constants.COURT_OF_APPEAL_CASE_ROUTE]: (theCase: Case) => @@ -299,15 +300,12 @@ export const findFirstInvalidStep = (steps: string[], theCase: Case) => { steps.includes(key), ) - if ( - stepsToCheck.every(([, validationFn]) => validationFn(theCase) === true) - ) { + if (stepsToCheck.every(([, validationFn]) => validationFn(theCase))) { return steps[steps.length - 1] } const [key] = - stepsToCheck.find(([, validationFn]) => validationFn(theCase) === false) || - [] + stepsToCheck.find(([, validationFn]) => !validationFn(theCase)) ?? [] return key } diff --git a/apps/judicial-system/web/src/utils/validate.ts b/apps/judicial-system/web/src/utils/validate.ts index 574b11f7b2f2..ec4c2843d69b 100644 --- a/apps/judicial-system/web/src/utils/validate.ts +++ b/apps/judicial-system/web/src/utils/validate.ts @@ -434,6 +434,11 @@ export const isDefenderStepValid = (workingCase: Case): boolean => { return Boolean(workingCase.prosecutor && defendantsAreValid()) } +export const isConclusionStepValid = (workingCase: Case): boolean => { + // TODO: Implement after selected action has been added as a field to the case + return true +} + export const isAdminUserFormValid = (user: User): boolean => { return Boolean( user.institution && diff --git a/libs/judicial-system/formatters/src/lib/formatters.ts b/libs/judicial-system/formatters/src/lib/formatters.ts index be856659ce42..1f0825501aba 100644 --- a/libs/judicial-system/formatters/src/lib/formatters.ts +++ b/libs/judicial-system/formatters/src/lib/formatters.ts @@ -104,10 +104,14 @@ export const getHumanReadableCaseIndictmentRulingDecision = ( rulingDecision?: CaseIndictmentRulingDecision, ) => { switch (rulingDecision) { - case CaseIndictmentRulingDecision.FINE: - return 'Viðurlagaákvæði' case CaseIndictmentRulingDecision.RULING: return 'Dómur' + case CaseIndictmentRulingDecision.FINE: + return 'Viðurlagaákvörðun' + case CaseIndictmentRulingDecision.DISMISSAL: + return 'Frávísun' + case CaseIndictmentRulingDecision.CANCELLATION: + return 'Niðurfelling máls' default: return 'Ekki skráð' } diff --git a/libs/judicial-system/types/src/lib/case.ts b/libs/judicial-system/types/src/lib/case.ts index 48cc5afc3bff..3c5e208a7185 100644 --- a/libs/judicial-system/types/src/lib/case.ts +++ b/libs/judicial-system/types/src/lib/case.ts @@ -231,6 +231,8 @@ export enum CaseAppealRulingDecision { export enum CaseIndictmentRulingDecision { RULING = 'RULING', FINE = 'FINE', + DISMISSAL = 'DISMISSAL', + CANCELLATION = 'CANCELLATION', } export enum IndictmentCaseReviewDecision { From b65f614cbdb2f2305e361df6d29fb0eaea698fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9tur=20Neisti=20Erlingsson?= Date: Thu, 30 May 2024 14:13:08 +0000 Subject: [PATCH 21/82] chore: Enable tracer only when its used (#15011) * chore: Enable tracer only when its used * rename to list * chore: nx format:write update dirty files * fix: typo * fix: tests --------- Co-authored-by: andes-it --- charts/identity-server/values.dev.yaml | 18 +++--- charts/identity-server/values.prod.yaml | 18 +++--- charts/identity-server/values.staging.yaml | 18 +++--- charts/islandis/values.dev.yaml | 64 +++++++++---------- charts/islandis/values.prod.yaml | 62 +++++++++--------- charts/islandis/values.staging.yaml | 58 ++++++++--------- charts/judicial-system/values.dev.yaml | 16 ++--- charts/judicial-system/values.prod.yaml | 16 ++--- charts/judicial-system/values.staging.yaml | 16 ++--- infra/src/dsl/basic.spec.ts | 2 +- infra/src/dsl/feature-values.spec.ts | 2 +- .../output-generators/map-to-helm-values.ts | 10 ++- infra/src/dsl/postgres.spec.ts | 2 +- 13 files changed, 155 insertions(+), 147 deletions(-) diff --git a/charts/identity-server/values.dev.yaml b/charts/identity-server/values.dev.yaml index 11448bc333ac..9f9bb6685b83 100644 --- a/charts/identity-server/values.dev.yaml +++ b/charts/identity-server/values.dev.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.dev01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.dev01.devland.is","https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -627,7 +627,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -698,7 +698,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://identity-server.dev01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/identity-server/values.prod.yaml b/charts/identity-server/values.prod.yaml index f1eb83b1f8da..7c68d1aa4457 100644 --- a/charts/identity-server/values.prod.yaml +++ b/charts/identity-server/values.prod.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://innskra.island.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -112,7 +112,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'https://service-portal-api.internal.island.is' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'true' PersistenceSettings__SessionsBaseAddress: 'https://sessions-api.internal.island.is' @@ -217,7 +217,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -285,7 +285,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' USER_NOTIFICATION_API_URL: 'https://user-notification.internal.island.is' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -372,7 +372,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -487,7 +487,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -542,7 +542,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -616,7 +616,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -687,7 +687,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://innskra.island.is/api' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/identity-server/values.staging.yaml b/charts/identity-server/values.staging.yaml index c495716079b6..fa80d892debd 100644 --- a/charts/identity-server/values.staging.yaml +++ b/charts/identity-server/values.staging.yaml @@ -12,7 +12,7 @@ auth-admin-web: LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://identity-server.staging01.devland.is/admin/api/auth' NEXT_PUBLIC_BACKEND_URL: '/backend' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -114,7 +114,7 @@ identity-server: IdentityServer__SigningCertificate__Path: '/etc/config/ids-signing.pfx' LOG_LEVEL: 'info' MeUserProfileApiSettings__BaseAddress: 'http://web-service-portal-api.service-portal.svc.cluster.local' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' PersistenceSettings__BaseAddress: 'http://web-services-auth-ids-api' PersistenceSettings__DelegationsCacheEnabled: 'false' PersistenceSettings__SessionsBaseAddress: 'http://web-services-sessions.services-sessions.svc.cluster.local' @@ -220,7 +220,7 @@ services-auth-admin-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' IDENTITY_SERVER_ISSUER_URL_LIST: '["https://identity-server.staging01.devland.is","https://innskra.island.is"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -288,7 +288,7 @@ services-auth-delegation-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' USER_NOTIFICATION_API_URL: 'http://web-user-notification.user-notification.svc.cluster.local' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -375,7 +375,7 @@ services-auth-ids-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' @@ -490,7 +490,7 @@ services-auth-ids-api-cleanup: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -545,7 +545,7 @@ services-auth-personal-representative: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -619,7 +619,7 @@ services-auth-personal-representative-public: DB_USER: 'servicesauth' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -690,7 +690,7 @@ services-auth-public-api: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/auth-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' PUBLIC_URL: 'https://identity-server.staging01.devland.is/api' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index f9e8ac904fef..157a05b3b376 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.dev01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -599,7 +599,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -814,7 +814,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -972,7 +972,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.dev01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.dev01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1033,7 +1033,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1097,7 +1097,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1165,7 +1165,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1280,7 +1280,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1371,7 +1371,7 @@ external-contracts-tests: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1514,7 +1514,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1660,7 +1660,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1847,7 +1847,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.dev01.devland.is/r1/IS-DEV' @@ -1943,7 +1943,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -2068,7 +2068,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2150,7 +2150,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2277,7 +2277,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.dev01.devland.is/minarsidur' @@ -2353,7 +2353,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2431,7 +2431,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2502,7 +2502,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2565,7 +2565,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2659,7 +2659,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2788,7 +2788,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' @@ -2863,7 +2863,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2933,7 +2933,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -3043,7 +3043,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3134,7 +3134,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications-reader.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -3238,7 +3238,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitydev.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-DEV/GOV/10001/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitydev.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3336,7 +3336,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.dev01.devland.is' grantNamespaces: @@ -3408,7 +3408,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-njkekqydiegezhr4vqpkfnw5la.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.dev01.devland.is' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 600f523374fd..31772b1426db 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -90,7 +90,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -194,7 +194,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.island.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -303,7 +303,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'island@island.is' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -589,7 +589,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'island@island.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Stafrænt Ísland' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Production' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -804,7 +804,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -965,7 +965,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'innskra.island.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://island.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1029,7 +1029,7 @@ contentful-apps: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1092,7 +1092,7 @@ contentful-entry-tagger-service: enabled: true env: LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1160,7 +1160,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS/EDU/4112043590/LBHI-Protected/brautskraning-v1' @@ -1275,7 +1275,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1382,7 +1382,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -1527,7 +1527,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1715,7 +1715,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.island.is/r1/IS' @@ -1811,7 +1811,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: [] grantNamespacesEnabled: false @@ -1936,7 +1936,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -2021,7 +2021,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2148,7 +2148,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_BASE_URL: 'https://island.is/minarsidur' @@ -2224,7 +2224,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'islandis' @@ -2302,7 +2302,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2373,7 +2373,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -2436,7 +2436,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' @@ -2530,7 +2530,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2659,7 +2659,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.whakos.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' @@ -2734,7 +2734,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -2807,7 +2807,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'application-system' @@ -2920,7 +2920,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3011,7 +3011,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -3115,7 +3115,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentity.b2clogin.com/skraidentity.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentity.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3213,7 +3213,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TRACKING_DOMAIN: 'island.is' grantNamespaces: @@ -3289,7 +3289,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-mw4w5c2m2g5edjrtvwbpzhkw24.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' XROAD_BASE_PATH: 'http://securityserver.island.is' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index a9f2d39d7529..eb40d3776d48 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -13,7 +13,7 @@ air-discount-scheme-api: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -92,7 +92,7 @@ air-discount-scheme-backend: IDENTITY_SERVER_CLIENT_ID: '@vegagerdin.is/clients/air-discount-scheme' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: 'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -200,7 +200,7 @@ air-discount-scheme-web: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://loftbru.staging01.devland.is' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -313,7 +313,7 @@ api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=1843' + NODE_OPTIONS: '--max-old-space-size=1843 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SEND_FROM_EMAIL: 'development@island.is' SERVERSIDE_FEATURES_ON: '' @@ -597,7 +597,7 @@ application-system-api: LOGIN_SERVICE_APPLICATION_RECIPIENT_EMAIL_ADDRESS: 'gunnar.ingi@fjr.is' LOGIN_SERVICE_APPLICATION_RECIPIENT_NAME: 'Gunnar Ingi' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' NOVA_USERNAME: 'IslandIs_User_Development' RECYCLING_FUND_GQL_BASE_PATH: 'http://web-skilavottord-ws.skilavottord.svc.cluster.local/app/skilavottord/api/graphql' @@ -812,7 +812,7 @@ application-system-api-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/application-system' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -971,7 +971,7 @@ consultation-portal: IDENTITY_SERVER_ISSUER_DOMAIN: 'identity-server.staging01.devland.is' LOG_LEVEL: 'info' NEXTAUTH_URL: 'https://beta.staging01.devland.is/samradsgatt/api/auth' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1035,7 +1035,7 @@ download-service: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/download-service' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REGULATIONS_ADMIN_URL: 'http://web-regulations-admin-backend.regulations-admin.svc.cluster.local' SERVERSIDE_FEATURES_ON: '' XROAD_AGRICULTURAL_UNIVERSITY_OF_ICELAND_PATH: 'IS-DEV/EDU/10056/LBHI-Protected/brautskraning-v1' @@ -1151,7 +1151,7 @@ endorsement-system-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1258,7 +1258,7 @@ icelandic-names-registry-backend: DB_USER: 'icelandic_names_registry_backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -1404,7 +1404,7 @@ license-api: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LICENSE_SERVICE_REDIS_NODES: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1589,7 +1589,7 @@ regulations-admin-backend: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/regulations-admin-api' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' XROAD_BASE_PATH_WITH_ENV: 'http://securityserver.staging01.devland.is/r1/IS-TEST' @@ -1685,7 +1685,7 @@ search-indexer-service: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=3686' + NODE_OPTIONS: '--max-old-space-size=3686 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: [] grantNamespacesEnabled: false @@ -1810,7 +1810,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_API: '/api/graphql' @@ -1893,7 +1893,7 @@ service-portal-api: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2020,7 +2020,7 @@ service-portal-api-worker: IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' ISLYKILL_CERT: '/etc/config/islyklar.p12' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_BASE_URL: 'https://beta.staging01.devland.is/minarsidur' @@ -2096,7 +2096,7 @@ services-documents: DB_USER: 'services_documents' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'islandis' @@ -2174,7 +2174,7 @@ services-sessions: DB_USER: 'services_sessions_read' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2245,7 +2245,7 @@ services-sessions-cleanup: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'services_sessions' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2308,7 +2308,7 @@ services-sessions-worker: DB_USER: 'services_sessions' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' REDIS_USE_SSL: 'true' SERVERSIDE_FEATURES_ON: '' @@ -2402,7 +2402,7 @@ services-university-gateway: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2531,7 +2531,7 @@ services-university-gateway-worker: IDENTITY_SERVER_CLIENT_ID: '@island.is/clients/university-gateway' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' REDIS_URL_NODE_01: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' @@ -2606,7 +2606,7 @@ skilavottord-web: API_URL: 'http://web-skilavottord-ws' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -2676,7 +2676,7 @@ skilavottord-ws: DB_USER: 'skilavottord' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'application-system' @@ -2786,7 +2786,7 @@ user-notification: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -2877,7 +2877,7 @@ user-notification-cleanup-worker: DB_REPLICAS_HOST: 'postgres-applications.internal' DB_USER: 'user_notification' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -2981,7 +2981,7 @@ user-notification-worker: NATIONAL_REGISTRY_B2C_ENDPOINT: 'https://skraidentitydev.b2clogin.com/skraidentitystaging.onmicrosoft.com/b2c_1_midlun_flow/oauth2/v2.0/token' NATIONAL_REGISTRY_B2C_PATH: 'IS-TEST/GOV/6503760649/SKRA-Cloud-Protected/Midlun-v1' NATIONAL_REGISTRY_B2C_SCOPE: 'https://skraidentitystaging.onmicrosoft.com/midlun/.default' - NODE_OPTIONS: '--max-old-space-size=345' + NODE_OPTIONS: '--max-old-space-size=345 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SERVICE_PORTAL_CLICK_ACTION_URL: 'https://island.is/minarsidur' USER_PROFILE_CLIENT_URL: 'http://web-service-portal-api.service-portal.svc.cluster.local' @@ -3080,7 +3080,7 @@ web: DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=691' + NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TRACKING_DOMAIN: 'beta.staging01.devland.is' grantNamespaces: @@ -3152,7 +3152,7 @@ xroad-collector: env: ELASTIC_NODE: 'https://vpc-search-q6hdtjcdlhkffyxvrnmzfwphuq.eu-west-1.es.amazonaws.com' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' NODE_TLS_REJECT_UNAUTHORIZED: '0' SERVERSIDE_FEATURES_ON: '' XROAD_BASE_PATH: 'http://securityserver.staging01.devland.is' diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index c20aacc92019..8d670725811a 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'true' S3_BUCKET: 'island-is-dev-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.dev01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.dev01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index 3a9c94c20cd8..2e9c2f0aadc8 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://ws.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-prod-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://innskra.island.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://rettarvorslugatt.island.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' grantNamespaces: - 'nginx-ingress-internal' diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index f93fd2f7c445..3cb6162b7289 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -32,7 +32,7 @@ judicial-system-api: HIDDEN_FEATURES: '' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=460' + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -116,7 +116,7 @@ judicial-system-backend: DOKOBIT_URL: 'https://developers.dokobit.com' EMAIL_REGION: 'eu-west-1' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=921' + NODE_OPTIONS: '--max-old-space-size=921 -r dd-trace/init' NOVA_ACCEPT_UNAUTHORIZED: 'false' S3_BUCKET: 'island-is-staging-upload-judicial-system' S3_REGION: 'eu-west-1' @@ -248,7 +248,7 @@ judicial-system-digital-mailbox-api: BACKEND_URL: 'http://web-judicial-system-backend' IDENTITY_SERVER_ISSUER_URL: 'https://identity-server.staging01.devland.is' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -320,7 +320,7 @@ judicial-system-message-handler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' SQS_DEAD_LETTER_QUEUE_NAME: 'sqs-judicial-system-dlq' SQS_QUEUE_NAME: 'sqs-judicial-system' @@ -383,7 +383,7 @@ judicial-system-robot-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' @@ -455,7 +455,7 @@ judicial-system-scheduler: env: BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' TIME_TO_LIVE_MINUTES: '30' grantNamespaces: @@ -508,7 +508,7 @@ judicial-system-web: API_URL: 'https://judicial-system.staging01.devland.is' INTERNAL_API_URL: 'http://web-judicial-system-api' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-external' @@ -574,7 +574,7 @@ judicial-system-xrd-api: AUDIT_TRAIL_USE_GENERIC_LOGGER: 'false' BACKEND_URL: 'http://web-judicial-system-backend' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230' + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' grantNamespaces: - 'nginx-ingress-internal' diff --git a/infra/src/dsl/basic.spec.ts b/infra/src/dsl/basic.spec.ts index e4201e50236e..f3d24bb8d736 100644 --- a/infra/src/dsl/basic.spec.ts +++ b/infra/src/dsl/basic.spec.ts @@ -103,7 +103,7 @@ describe('Basic serialization', () => { DB_NAME: 'api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=460', + NODE_OPTIONS: '--max-old-space-size=460 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) diff --git a/infra/src/dsl/feature-values.spec.ts b/infra/src/dsl/feature-values.spec.ts index eba9a6d3cf28..9ee13cb2f03d 100644 --- a/infra/src/dsl/feature-values.spec.ts +++ b/infra/src/dsl/feature-values.spec.ts @@ -94,7 +94,7 @@ describe('Feature-deployment support', () => { DB_NAME: 'feature_feature_A_graphql', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230', + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', DB_EXTENSIONS: 'foo', diff --git a/infra/src/dsl/output-generators/map-to-helm-values.ts b/infra/src/dsl/output-generators/map-to-helm-values.ts index 7bead10451ff..24c5d7672082 100644 --- a/infra/src/dsl/output-generators/map-to-helm-values.ts +++ b/infra/src/dsl/output-generators/map-to-helm-values.ts @@ -46,6 +46,12 @@ const serializeService: SerializeMethod = async ( namespace, securityContext, } = serviceDef + const hackListForNonExistentTracer = [ + 'application-system-form', + 'github-actions-cache', + 'portals-admin', + 'island-ui-storybook', + ] const result: HelmService = { enabled: true, grantNamespaces: grantNamespaces, @@ -82,7 +88,9 @@ const serializeService: SerializeMethod = async ( }, securityContext, } - + if (!hackListForNonExistentTracer.includes(serviceDef.name)) { + result.env.NODE_OPTIONS += ' -r dd-trace/init' + } // command and args if (serviceDef.cmds) { result.command = [serviceDef.cmds] diff --git a/infra/src/dsl/postgres.spec.ts b/infra/src/dsl/postgres.spec.ts index ddb7d0753888..7c7e73c68652 100644 --- a/infra/src/dsl/postgres.spec.ts +++ b/infra/src/dsl/postgres.spec.ts @@ -41,7 +41,7 @@ describe('Postgres', () => { DB_NAME: 'service_portal_api', DB_HOST: 'a', DB_REPLICAS_HOST: 'a', - NODE_OPTIONS: '--max-old-space-size=230', + NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init', SERVERSIDE_FEATURES_ON: '', LOG_LEVEL: 'info', }) From c4f12fb7538336adf5a0ee2029320fea32f7f994 Mon Sep 17 00:00:00 2001 From: lommi Date: Thu, 30 May 2024 14:55:50 +0000 Subject: [PATCH 22/82] chore: upgrade node version (#14985) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: single source of truth for node version * fix: hash key * fix: update docker images * chore: nx format:write update dirty files * fix: deps * chore: nx format:write update dirty files * fix: build arg * fix: remove echo * Update scripts/ci/Dockerfile Co-authored-by: Jón Levy * Update .github/workflows/pullrequest.yml Co-authored-by: Jón Levy * Update .github/workflows/push.yml Co-authored-by: Jón Levy * Update scripts/ci/Dockerfile Co-authored-by: Jón Levy * Update scripts/ci/10_prepare-docker-deps.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update scripts/ci/10_prepare-docker-deps.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: formatting * fix: formatting * chore: nx format:write update dirty files * fix: sparse checkout * Update .github/workflows/push.yml Co-authored-by: Jón Levy * chore: nx format:write update dirty files * fix: nodejs image tag * fix: image tag * fix: skip fetch * Update infra/scripts/Dockerfile Co-authored-by: Jón Levy * Update infra/scripts/Dockerfile Co-authored-by: Jón Levy * fix: ble * fix: debug * fix: oops * chore: nx format:write update dirty files * fix: build * fix: affect all * fix: test skipping base tag * chore: nx format:write update dirty files * fix: update script * fix: build * fix: main * fix: build * fix: revert * fix: remove trash * fix: remove error * fix: ble * add debug * fix: ok * fix: ok * fix: bug * fix: bad test * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * fix: ok * chore: nx format:write update dirty files * fix: revert * fix: prog * fix: build * fix: version * chore: nx format:write update dirty files --------- Co-authored-by: andes-it Co-authored-by: Jón Levy Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .github/actions/dist/main.js | 6 ++- .github/actions/main.ts | 5 +- .github/actions/package.json | 2 +- .github/actions/tsconfig.json | 2 +- .github/actions/unit-test/action.yml | 4 +- .github/actions/yarn.lock | 10 ++-- .github/workflows/config-values.yaml | 8 +-- .github/workflows/pullrequest.yml | 36 ++++++------- .github/workflows/push.yml | 77 +++++++++++++++++++--------- infra/scripts/Dockerfile | 5 +- scripts/ci/10_prepare-docker-deps.sh | 5 ++ scripts/ci/Dockerfile | 5 +- scripts/ci/_common.mjs | 11 ++++ scripts/ci/_nx-affected-targets.sh | 3 +- scripts/ci/get-node-modules-hash.mjs | 47 +++++++++++++++++ scripts/ci/get-node-version.mjs | 60 ++++++++++++++++++++++ 16 files changed, 221 insertions(+), 65 deletions(-) create mode 100644 scripts/ci/_common.mjs create mode 100755 scripts/ci/get-node-modules-hash.mjs create mode 100755 scripts/ci/get-node-version.mjs diff --git a/.github/actions/dist/main.js b/.github/actions/dist/main.js index 7069298320f8..d4ad424ecedd 100644 --- a/.github/actions/dist/main.js +++ b/.github/actions/dist/main.js @@ -26173,7 +26173,9 @@ function findBestGoodRefPR(diffWeight, git, githubApi, headBranch, baseBranch, p if (prRun) { log(`Found a PR run candidate: ${JSON.stringify(prRun)}`); try { - const tempBranch = `${headBranch}-${Math.round(Math.random() * 1e6)}`; + const tempBranch = `${headBranch}-${Math.round( + Math.random() * 1e6 + )}`; yield git.checkoutBranch(tempBranch, prRun.base_commit); log(`Branch checked out`); const mergeCommitSha = yield git.merge(prRun.head_commit); @@ -26332,7 +26334,7 @@ var SimpleGit = class { // main.ts var FULL_REBUILD_NEEDED = "full_rebuild_needed"; (() => __async(exports, null, function* () { - if (process.env.NX_AFFECTED_ALL === "true") { + if (process.env.NX_AFFECTED_ALL === "true" || process.env.TEST_EVERYTHING === "true") { console.log(FULL_REBUILD_NEEDED); return; } diff --git a/.github/actions/main.ts b/.github/actions/main.ts index 75872b21f061..5a9c0be3abe0 100644 --- a/.github/actions/main.ts +++ b/.github/actions/main.ts @@ -7,7 +7,10 @@ import { WorkflowID } from './git-action-status' const FULL_REBUILD_NEEDED = 'full_rebuild_needed' ;(async () => { - if (process.env.NX_AFFECTED_ALL === 'true') { + if ( + process.env.NX_AFFECTED_ALL === 'true' || + process.env.TEST_EVERYTHING === 'true' + ) { console.log(FULL_REBUILD_NEEDED) return } diff --git a/.github/actions/package.json b/.github/actions/package.json index 061faaf0a65e..28ff702a834d 100644 --- a/.github/actions/package.json +++ b/.github/actions/package.json @@ -19,7 +19,7 @@ "@octokit/rest": "19.0.4", "@types/debug": "4.1.7", "@types/jest": "^27.4.1", - "@types/node": "20.11.4", + "@types/node": "20.12.12", "debug": "4.3.4", "esbuild": "0.15.10", "esbuild-runner": "2.2.1", diff --git a/.github/actions/tsconfig.json b/.github/actions/tsconfig.json index ff324a0e1d98..1c3a88d4b3fb 100644 --- a/.github/actions/tsconfig.json +++ b/.github/actions/tsconfig.json @@ -12,7 +12,7 @@ "target": "es2015", "module": "esnext", "typeRoots": ["node_modules/@types"], - "lib": ["es2019", "esnext.array"], + "lib": ["es2019", "esnext.array", "esnext"], "skipLibCheck": true, "skipDefaultLibCheck": true, "allowSyntheticDefaultImports": true, diff --git a/.github/actions/unit-test/action.yml b/.github/actions/unit-test/action.yml index 2d26e5bb94e0..dcea4d884e94 100644 --- a/.github/actions/unit-test/action.yml +++ b/.github/actions/unit-test/action.yml @@ -36,9 +36,9 @@ runs: run: npm install -g yarn shell: bash - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn diff --git a/.github/actions/yarn.lock b/.github/actions/yarn.lock index 366f3c0d008f..6a7376cdfd0d 100644 --- a/.github/actions/yarn.lock +++ b/.github/actions/yarn.lock @@ -1610,12 +1610,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:20.11.4": - version: 20.11.4 - resolution: "@types/node@npm:20.11.4" +"@types/node@npm:20.12.12": + version: 20.12.12 + resolution: "@types/node@npm:20.12.12" dependencies: undici-types: ~5.26.4 - checksum: b9cf2c5397ea31f3355656edd204aee777a36db75b79b8b7aba2bed7ea5b29914fa808489da5c632c5eddbb33c3106188bef0bff3b7648bd39aa50dee466a73b + checksum: 5373983874b9af7c216e7ca5d26b32a8d9829c703a69f1e66f2113598b5be8582c0e009ca97369f1ec9a6282b3f92812208d06eb1e9fc3bd9b939b022303d042 languageName: node linkType: hard @@ -1715,7 +1715,7 @@ __metadata: "@octokit/rest": 19.0.4 "@types/debug": 4.1.7 "@types/jest": ^27.4.1 - "@types/node": 20.11.4 + "@types/node": 20.12.12 debug: 4.3.4 esbuild: 0.15.10 esbuild-runner: 2.2.1 diff --git a/.github/workflows/config-values.yaml b/.github/workflows/config-values.yaml index a5e5655f5e81..af314b1368dd 100644 --- a/.github/workflows/config-values.yaml +++ b/.github/workflows/config-values.yaml @@ -61,9 +61,9 @@ jobs: - uses: actions/checkout@v3 if: ${{ github.event_name != 'pull_request' }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -109,9 +109,9 @@ jobs: matrix: ${{ fromJson(needs.prepare.outputs.ENVS) }} steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Cache for NodeJS dependencies id: node-modules diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index ce3186ec3ea7..499977254e35 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -45,9 +45,9 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18.8.0' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -80,11 +80,9 @@ jobs: - name: Calculate cache key for node modules id: calculate_node_modules_hash run: | - PACKAGE_JSON_HASH=$(cat package.json | jq '{resolutions,dependencies,devDependencies}' | sha1sum -t | cut -f1 -d" ") - echo "PACKAGE_JSON_HASH: $PACKAGE_JSON_HASH" - export NODE_MODULES_HASH=${{ runner.os }}-${{ hashFiles('yarn.lock') }}-$PACKAGE_JSON_HASH - echo "NODE_MODULES_HASH: $NODE_MODULES_HASH" - echo "node-modules-hash=$NODE_MODULES_HASH" >> $GITHUB_OUTPUT + HASH="$(./scripts/ci/get-node-modules-hash.mjs)" + echo "node-modules-hash: ${HASH}" + echo "node-modules-hash=${HASH}" >> $GITHUB_OUTPUT - name: Calculate cache keys for generated files id: calculate_generated_files_cache_key @@ -249,9 +247,9 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -310,9 +308,9 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -373,9 +371,9 @@ jobs: path: node_modules key: ${{ needs.prepare.outputs.node-modules-hash }}-yarn - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -416,9 +414,9 @@ jobs: - uses: actions/checkout@v3 if: ${{ github.ref == 'ref/heads/main' }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -460,9 +458,9 @@ jobs: matrix: ${{ fromJson(needs.prepare.outputs.LINT_CHUNKS) }} steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn - name: Cache for NodeJS dependencies - host OS @@ -509,9 +507,9 @@ jobs: if: needs.prepare.outputs.BUILD_CHUNKS steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn - name: Cache for NodeJS dependencies - host OS diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 744f17f62839..fbfc16389a00 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -48,6 +48,7 @@ jobs: CREATE_PATTERNS: ^release/ PRE_RELEASE_PATTERN: ^pre-release/ outputs: + NODE_IMAGE_TAG: ${{ steps.git-branch.outputs.NODE_IMAGE_TAG }} GIT_BRANCH: ${{ steps.git-branch.outputs.GIT_BRANCH }} GIT_BRANCH_DEPLOY: ${{ steps.git-branch-deploy.outputs.GIT_BRANCH_DEPLOY }} FEATURE_NAME: ${{ steps.git-branch-deploy.outputs.FEATURE_NAME }} @@ -75,7 +76,6 @@ jobs: echo "GIT_BRANCH_DEPLOY=${GIT_BRANCH_DEPLOY}" >> $GITHUB_OUTPUT echo "GIT_BRANCH_DEPLOY=$GIT_BRANCH_DEPLOY" >> $GITHUB_ENV echo "FEATURE_NAME=$(echo $GIT_BRANCH_DEPLOY | cut -d"/" -f2- | tr -cd '[:alnum:]-' | tr '[:upper:]' '[:lower:]' | cut -c1-50)" >> $GITHUB_OUTPUT - - name: Check if we want to run workflow id: should-run env: @@ -158,6 +158,7 @@ jobs: outputs: TEST_CHUNKS: ${{ steps.test_projects.outputs.CHUNKS }} DOCKER_TAG: ${{ steps.docker_tags.outputs.DOCKER_TAG }} + NODE_IMAGE_TAG: ${{ steps.nodejs_image.outputs.NODE_IMAGE_TAG }} LAST_GOOD_BUILD_DOCKER_TAG: ${{ steps.git_nx_base.outputs.LAST_GOOD_BUILD_DOCKER_TAG }} UNAFFECTED: ${{ steps.unaffected.outputs.UNAFFECTED }} BUILD_CHUNKS: ${{ steps.build_map.outputs.BUILD_CHUNKS }} @@ -168,9 +169,9 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18.8.0' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -235,6 +236,15 @@ jobs: path: event.json retention-days: 60 + - name: Generate nodejs image tag + id: nodejs_image + continue-on-error: false + run: | + export NODE_IMAGE_TAG="$(./scripts/ci/get-node-version.mjs)" + echo "NODE_IMAGE_TAG: ${NODE_IMAGE_TAG}" + echo "NODE_IMAGE_TAG=${NODE_IMAGE_TAG}" >> $GITHUB_OUTPUT + echo "NODE_IMAGE_TAG=${NODE_IMAGE_TAG}" >> $GITHUB_ENV + echo "**NODE_IMAGE_TAG** ${NODE_IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY - name: Generate docker image tag id: docker_tags run: | @@ -277,11 +287,9 @@ jobs: - name: Calculate cache key for node modules id: calculate_node_modules_hash run: | - PACKAGE_JSON_HASH=$(cat package.json | jq '{resolutions,dependencies,devDependencies}' | sha1sum -t | cut -f1 -d" ") - echo "PACKAGE_JSON_HASH: $PACKAGE_JSON_HASH" - export NODE_MODULES_HASH=${{ runner.os }}-${{ hashFiles('yarn.lock') }}-$PACKAGE_JSON_HASH - echo "NODE_MODULES_HASH: $NODE_MODULES_HASH" - echo "node-modules-hash=$NODE_MODULES_HASH" >> $GITHUB_OUTPUT + HASH="$(./scripts/ci/get-node-modules-hash.mjs)" + echo "node-modules-hash: ${HASH}" + echo "node-modules-hash=${HASH}" >> $GITHUB_OUTPUT - name: Calculate cache keys for generated files id: calculate_generated_files_cache_key @@ -306,6 +314,15 @@ jobs: if: steps.node-modules.outputs.cache-hit != 'true' run: ./scripts/ci/10_prepare-host-deps.sh + - name: Set Test Everything true + run: | + echo "TEST_EVERYTHING=true" >> $GITHUB_ENV + if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test everything') + + - name: Set Test Everything false + run: echo "TEST_EVERYTHING=false" >> $GITHUB_ENV + if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'test everything') + - name: Preparing BASE tags id: git_nx_base env: @@ -370,7 +387,8 @@ jobs: - name: Building NodeJS dependencies if: steps.cache-deps.outputs.cache-hit != 'true' || steps.cache-deps-base.outputs.cache-hit != 'true' - run: ./scripts/ci/10_prepare-docker-deps.sh + run: | + ./scripts/ci/10_prepare-docker-deps.sh - name: set BRANCH env var run: echo "BRANCH=$GIT_BRANCH" >> $GITHUB_ENV @@ -452,9 +470,9 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' - name: Setup yarn run: npm install -g yarn @@ -505,6 +523,7 @@ jobs: AFFECTED_ALL: ${{ secrets.AFFECTED_ALL }} GIT_BRANCH: ${{ needs.pre-checks.outputs.GIT_BRANCH}} DOCKER_TAG: ${{ needs.prepare.outputs.DOCKER_TAG}} + NODE_IMAGE_TAG: ${{ needs.prepare.outputs.NODE_IMAGE_TAG}} PUBLISH: true strategy: fail-fast: false @@ -519,22 +538,17 @@ jobs: echo "AFFECTED_PROJECTS=$AFFECTED_PROJECTS" >> $GITHUB_ENV echo "DOCKER_TYPE=$DOCKER_TYPE" >> $GITHUB_ENV continue-on-error: true - - uses: actions/setup-node@v3 - with: - node-version: '18' + - uses: actions/checkout@v3 if: steps.gather.outcome == 'success' - - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: '18' + node-version-file: 'package.json' if: steps.gather.outcome == 'success' - name: Setup yarn run: npm install -g yarn if: steps.gather.outcome == 'success' - - uses: actions/checkout@v3 - if: steps.gather.outcome == 'success' - name: Cache for generated files id: generated-files-cache if: steps.gather.outcome == 'success' @@ -605,15 +619,25 @@ jobs: continue-on-error: true id: dockerbuild if: steps.gather.outcome == 'success' - run: ./scripts/ci/run-in-parallel.sh 90_$DOCKER_TYPE env: - EXTRA_DOCKER_BUILD_ARGS: '--build-arg DOCKER_IMAGE_REGISTRY=${{ env.DOCKER_BASE_IMAGE_REGISTRY }} --build-arg GIT_SHA=${{ github.sha }}' + NODE_IMAGE_TAG: ${{ needs.prepare.outputs.NODE_IMAGE_TAG }} + SHA: ${{ github.sha }} + DOCKER_BASE_IMAGE_REGISTRY: ${{ env.DOCKER_BASE_IMAGE_REGISTRY }} + run: | + echo Node image tag is: $NODE_IMAGE_TAG + export EXTRA_DOCKER_BUILD_ARGS="--build-arg DOCKER_IMAGE_REGISTRY=$DOCKER_BASE_IMAGE_REGISTRY --build-arg GIT_SHA=$SHA --build-arg NODE_IMAGE_TAG=$NODE_IMAGE_TAG" + ./scripts/ci/run-in-parallel.sh 90_$DOCKER_TYPE - - name: Building Docker images Retry #This only exists until GHA starts supporting this + - name: Building Docker images Retry if: steps.gather.outcome == 'success' && steps.dockerbuild.outcome == 'failure' - run: ./scripts/ci/run-in-parallel.sh 90_$DOCKER_TYPE env: - EXTRA_DOCKER_BUILD_ARGS: '--build-arg DOCKER_IMAGE_REGISTRY=${{ env.DOCKER_BASE_IMAGE_REGISTRY }} --build-arg GIT_SHA=${{ github.sha }}' + NODE_IMAGE_TAG: ${{ needs.prepare.outputs.NODE_IMAGE_TAG }} + SHA: ${{ github.sha }} + DOCKER_BASE_IMAGE_REGISTRY: ${{ env.DOCKER_BASE_IMAGE_REGISTRY }} + run: | + echo Node image tag is: $NODE_IMAGE_TAG + export EXTRA_DOCKER_BUILD_ARGS="--build-arg DOCKER_IMAGE_REGISTRY=$DOCKER_BASE_IMAGE_REGISTRY --build-arg GIT_SHA=$SHA --build-arg NODE_IMAGE_TAG=$NODE_IMAGE_TAG" + ./scripts/ci/run-in-parallel.sh 90_$DOCKER_TYPE helm-docker-build: needs: @@ -628,6 +652,7 @@ jobs: FEATURE_NAME: ${{ needs.pre-checks.outputs.FEATURE_NAME }} DOCKER_TAG: ${{ needs.prepare.outputs.DOCKER_TAG}} GIT_BRANCH: ${{ needs.pre-checks.outputs.GIT_BRANCH }} + NODE_IMAGE_TAG: ${{ needs.prepare.outputs.NODE_IMAGE_TAG }} steps: - uses: actions/checkout@v3 @@ -647,6 +672,9 @@ jobs: - name: Docker build image working-directory: infra run: | + echo Registry is: ${{env.DOCKER_BASE_IMAGE_REGISTRY}} + echo Image tag is: ${{env.NODE_IMAGE_TAG}} + export EXTRA_DOCKER_BUILD_ARGS="--build-arg DOCKER_IMAGE_REGISTRY=${{env.DOCKER_BASE_IMAGE_REGISTRY}} --build-arg NODE_IMAGE_TAG=${{env.NODE_IMAGE_TAG}}" ./scripts/build-docker-container.sh $DOCKER_TAG echo "COMMENT<> $GITHUB_ENV echo "Affected services are: ${{needs.prepare.outputs.IMAGES}}" >> $GITHUB_ENV @@ -654,7 +682,6 @@ jobs: echo 'EOF' >> $GITHUB_ENV env: PUBLISH: 'true' - EXTRA_DOCKER_BUILD_ARGS: '--build-arg DOCKER_IMAGE_REGISTRY=${{ env.DOCKER_BASE_IMAGE_REGISTRY }}' - name: Retag as latest if: ${{ env.GIT_BRANCH == 'main' && env.NX_AFFECTED_ALL != 'true' }} diff --git a/infra/scripts/Dockerfile b/infra/scripts/Dockerfile index 5a5912fc33b6..56cf15f55d5a 100644 --- a/infra/scripts/Dockerfile +++ b/infra/scripts/Dockerfile @@ -1,9 +1,10 @@ ARG DOCKER_IMAGE_REGISTRY=public.ecr.aws -FROM $DOCKER_IMAGE_REGISTRY/docker/library/node:18-alpine3.15 as runner +ARG NODE_IMAGE_TAG +FROM ${DOCKER_IMAGE_REGISTRY}/docker/library/node:${NODE_IMAGE_TAG} as runner RUN apk add postgresql-client bash -FROM $DOCKER_IMAGE_REGISTRY/docker/library/node:18-alpine3.15 as build +FROM ${DOCKER_IMAGE_REGISTRY}/docker/library/node:${NODE_IMAGE_TAG} as build ENV NODE_OPTIONS=--openssl-legacy-provider diff --git a/scripts/ci/10_prepare-docker-deps.sh b/scripts/ci/10_prepare-docker-deps.sh index a0ff050121a3..d0513560c150 100755 --- a/scripts/ci/10_prepare-docker-deps.sh +++ b/scripts/ci/10_prepare-docker-deps.sh @@ -7,11 +7,15 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source "$DIR"/_common.sh mkdir -p "$PROJECT_ROOT"/cache + +NODE_IMAGE_TAG=${NODE_IMAGE_TAG:-$(./scripts/ci/get-node-version.mjs)} + docker buildx create --driver docker-container --use || true docker buildx build \ --platform=linux/amd64 \ --cache-to=type=local,dest="$PROJECT_ROOT"/cache \ + --build-arg NODE_IMAGE_TAG="$NODE_IMAGE_TAG" \ -f "${DIR}"/Dockerfile \ --target=deps \ "$PROJECT_ROOT" @@ -20,6 +24,7 @@ docker buildx build \ --platform=linux/amd64 \ --cache-from=type=local,src="$PROJECT_ROOT"/cache \ --cache-to=type=local,dest="$PROJECT_ROOT"/cache_output \ + --build-arg NODE_IMAGE_TAG="$NODE_IMAGE_TAG" \ -f "${DIR}"/Dockerfile \ --target=output-base \ "$PROJECT_ROOT" diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile index e5c182e323eb..0d482c1203d7 100644 --- a/scripts/ci/Dockerfile +++ b/scripts/ci/Dockerfile @@ -1,7 +1,8 @@ # This is a multi-stage Dockerfile which contains all CI-related operations as well as images to be deployed in production ARG PLAYWRIGHT_VERSION ARG DOCKER_IMAGE_REGISTRY=public.ecr.aws -FROM $DOCKER_IMAGE_REGISTRY/docker/library/node:18-alpine3.15 as deps +ARG NODE_IMAGE_TAG +FROM ${DOCKER_IMAGE_REGISTRY}/docker/library/node:${NODE_IMAGE_TAG} as deps RUN apk add -U git @@ -32,7 +33,7 @@ ENV NODE_OPTIONS="--max-old-space-size=8192" RUN yarn run build ${APP} --prod -FROM $DOCKER_IMAGE_REGISTRY/docker/library/node:18-alpine3.15 as output-base +FROM ${DOCKER_IMAGE_REGISTRY}/docker/library/node:${NODE_IMAGE_TAG} as output-base # this is base image for containers that are to be deployed ARG GIT_BRANCH ARG GIT_SHA diff --git a/scripts/ci/_common.mjs b/scripts/ci/_common.mjs new file mode 100644 index 000000000000..b52c5bd44126 --- /dev/null +++ b/scripts/ci/_common.mjs @@ -0,0 +1,11 @@ +import { readFile } from 'node:fs/promises' +import { dirname, resolve } from 'path' +import { fileURLToPath } from 'url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +export const ROOT = resolve(__dirname, '..', '..') + +export async function getPackageJSON(filePath = resolve(ROOT, 'package.json')) { + const content = JSON.parse(await readFile(filePath, 'utf-8')) + return content +} diff --git a/scripts/ci/_nx-affected-targets.sh b/scripts/ci/_nx-affected-targets.sh index 5ba344dde326..3d861a2a0194 100755 --- a/scripts/ci/_nx-affected-targets.sh +++ b/scripts/ci/_nx-affected-targets.sh @@ -8,12 +8,13 @@ source "$DIR"/_common.sh export HEAD=${HEAD:-HEAD} export BASE=${BASE:-main} NX_AFFECTED_ALL=${NX_AFFECTED_ALL:-} +TEST_EVERYTHING=${TEST_EVERYTHING:-} # This is a helper script to find NX affected projects for a specific target AFFECTED_ALL=${AFFECTED_ALL:-} # Could be used for forcing all projects to be affected (set or create `secret` in GitHub with the name of this variable set to the name of the branch that should be affected, prefixed with the magic string `7913-`) BRANCH=${BRANCH:-$GITHUB_HEAD_REF} -if [[ (-n "$BRANCH" && -n "$AFFECTED_ALL" && "$AFFECTED_ALL" == "7913-$BRANCH") || (-n "$NX_AFFECTED_ALL" && "$NX_AFFECTED_ALL" == "true") ]]; then +if [[ (-n "$BRANCH" && -n "$AFFECTED_ALL" && "$AFFECTED_ALL" == "7913-$BRANCH") || (-n "$NX_AFFECTED_ALL" && "$NX_AFFECTED_ALL" == "true") || (-n "$TEST_EVERYTHING" && "$TEST_EVERYTHING" == "true")]]; then EXTRA_ARGS="" else EXTRA_ARGS=(--affected --base "$BASE" --head "$HEAD") diff --git a/scripts/ci/get-node-modules-hash.mjs b/scripts/ci/get-node-modules-hash.mjs new file mode 100755 index 000000000000..45ee96b9bb3e --- /dev/null +++ b/scripts/ci/get-node-modules-hash.mjs @@ -0,0 +1,47 @@ +#!/usr/bin/env node +import { readFile } from 'node:fs/promises' +import { resolve } from 'node:path' +import { arch, platform } from 'os' +import crypto from 'node:crypto' + +import { ROOT, getPackageJSON } from './_common.mjs' + +process.stdout.write( + `${getPlatformString()}-${await getYarnLockHash()}-${await getPackageHash()}-${await getNodeVersionString()}`, +) + +async function getNodeVersionString() { + const content = await getPackageJSON() + const nodeVersion = content?.engines?.node + const yarnVersion = content?.engines?.yarn + if (!nodeVersion) { + throw new Error('Node version not defined') + } + if (!yarnVersion) { + throw new Error('Yarn version not defined') + } + + return `${nodeVersion}-${yarnVersion}` +} + +function getPlatformString() { + return `${platform()}-${arch()}` +} + +async function getPackageHash( + keys = ['resolutions', 'dependencies', 'devDependencies'], +) { + const content = await getPackageJSON() + const value = keys.reduce((a, b) => { + return { + ...a, + [b]: content[b], + } + }, {}) + return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex') +} + +async function getYarnLockHash(filePath = resolve(ROOT, 'yarn.lock')) { + const content = await readFile(filePath, 'utf-8') + return crypto.createHash('sha256').update(content).digest('hex') +} diff --git a/scripts/ci/get-node-version.mjs b/scripts/ci/get-node-version.mjs new file mode 100755 index 000000000000..0c7de8b3e6c0 --- /dev/null +++ b/scripts/ci/get-node-version.mjs @@ -0,0 +1,60 @@ +#!/usr/bin/env node +import { getPackageJSON } from './_common.mjs' + +const DOCKERHUB_BASE_URL = + 'https://hub.docker.com/v2/repositories/library/node/tags?page_size=100' + +const nodeVersion = await getPackageVersion() +const version = await getVersion(nodeVersion) + +if (!version) { + console.error(`Failed getting docker image for ${nodeVersion}`) + process.exit(1) +} +process.stdout.write(version) + +async function getVersion( + version, + withAlpine = true, + architecture = 'amd64', + url = null, +) { + try { + const baseURL = url ?? DOCKERHUB_BASE_URL + const response = await fetch(baseURL) + const data = await response.json() + + const filteredTags = data.results.filter((tag) => { + const isVersionMatch = tag.name.startsWith(version) + const isAlpine = withAlpine ? tag.name.includes('alpine') : true + const isArchitectureMatch = tag.images.some( + (image) => image.architecture === architecture, + ) + return isVersionMatch && isAlpine && isArchitectureMatch + }) + + const latestTag = filteredTags.sort((a, b) => + b.last_updated.localeCompare(a.last_updated), + )[0] + + if (latestTag) { + return latestTag.name + } + const nextUrl = data.next + if (!nextUrl) { + return null + } + return getVersion(version, withAlpine, architecture, nextUrl) + } catch (error) { + console.error('Failed to fetch the Docker tags', error) + } +} + +async function getPackageVersion() { + const content = await getPackageJSON() + const version = content.engines?.node + if (!version) { + throw new Error(`Cannot find node version`) + } + return version +} From ffda333bdc09797de352cbb327d98e984826ce35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Thu, 30 May 2024 15:16:24 +0000 Subject: [PATCH 23/82] fix(service-portal-health): small refactor (#14939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Þorkell Máni Þorkelsson Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../overview/models/insuranceOverview.model.ts | 6 +++--- .../src/lib/overview/overview.service.ts | 17 ++++++++--------- libs/service-portal/health/src/lib/messages.ts | 4 ++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libs/api/domains/rights-portal/src/lib/overview/models/insuranceOverview.model.ts b/libs/api/domains/rights-portal/src/lib/overview/models/insuranceOverview.model.ts index da214cc700b8..fefbf68dbc36 100644 --- a/libs/api/domains/rights-portal/src/lib/overview/models/insuranceOverview.model.ts +++ b/libs/api/domains/rights-portal/src/lib/overview/models/insuranceOverview.model.ts @@ -10,10 +10,10 @@ export class InsuranceOverview { explanation?: string @Field(() => Date, { nullable: true }) - from?: Date | null + from?: Date - @Field(() => InsuranceStatus) - status!: InsuranceStatus + @Field(() => InsuranceStatus, { nullable: true }) + status?: InsuranceStatus @Field(() => Int, { nullable: true }) maximumPayment?: number | null diff --git a/libs/api/domains/rights-portal/src/lib/overview/overview.service.ts b/libs/api/domains/rights-portal/src/lib/overview/overview.service.ts index f2a737865fbc..2ffae61a2915 100644 --- a/libs/api/domains/rights-portal/src/lib/overview/overview.service.ts +++ b/libs/api/domains/rights-portal/src/lib/overview/overview.service.ts @@ -29,12 +29,9 @@ export class OverviewService { } if (!data.fileName || !data.contentType || !data.data) { - this.logger.warn( - 'Missing data for getInsuranceConfirmation from external service', - { - category: LOG_CATEGORY, - }, - ) + this.logger.warn('Missing data from external service', { + category: LOG_CATEGORY, + }) return null } @@ -45,14 +42,16 @@ export class OverviewService { } } - async getInsuranceOverview(user: User): Promise { + async getInsuranceOverview(user: User): Promise { const data = await this.api .withMiddleware(new AuthMiddleware(user as Auth)) .getInsuranceOverview() .catch(handle404) if (!data) { - return null + return { + isInsured: false, + } } const codeEnum: InsuranceStatusType | undefined = @@ -65,7 +64,7 @@ export class OverviewService { return { isInsured: !!data.isInsured, explanation: data.explanation ?? '', - from: data.from, + from: data.from ?? undefined, maximumPayment: data.maximumPayment, ehicCardExpiryDate: data.ehicCardExpiryDate ?? undefined, status: { diff --git a/libs/service-portal/health/src/lib/messages.ts b/libs/service-portal/health/src/lib/messages.ts index 077b28f60967..6f09499b1efe 100644 --- a/libs/service-portal/health/src/lib/messages.ts +++ b/libs/service-portal/health/src/lib/messages.ts @@ -206,6 +206,10 @@ export const messages = defineMessages({ id: 'sp.health:no-health-insurance', defaultMessage: 'Þú ert ekki með sjúkratryggingu', }, + noHealthInsuranceMessage: { + id: 'sp.health:no-health-insurance-message', + defaultMessage: 'Síðasta trygging: {arg}', + }, paymentTarget: { id: 'sp.health:payment-target', defaultMessage: 'Greiðslumark', From f6e09da16d7a1ed05851d70434e0a9129fa637f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9tur=20Neisti=20Erlingsson?= Date: Thu, 30 May 2024 15:22:06 +0000 Subject: [PATCH 24/82] fix: Add Service Portal to list of non-tracer apps (#15022) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- charts/islandis/values.dev.yaml | 2 +- charts/islandis/values.prod.yaml | 2 +- charts/islandis/values.staging.yaml | 2 +- infra/src/dsl/output-generators/map-to-helm-values.ts | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index 157a05b3b376..9c94bf82e58c 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -2068,7 +2068,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'dev' SI_PUBLIC_GRAPHQL_API: '/api/graphql' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 31772b1426db..3fe5bf556a0c 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -1936,7 +1936,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' SI_PUBLIC_ENVIRONMENT: 'prod' SI_PUBLIC_GRAPHQL_API: '/api/graphql' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index eb40d3776d48..80b419e7ca0a 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -1810,7 +1810,7 @@ service-portal: env: BASEPATH: '/minarsidur' LOG_LEVEL: 'info' - NODE_OPTIONS: '--max-old-space-size=230 -r dd-trace/init' + NODE_OPTIONS: '--max-old-space-size=230' SERVERSIDE_FEATURES_ON: '' SI_PUBLIC_ENVIRONMENT: 'staging' SI_PUBLIC_GRAPHQL_API: '/api/graphql' diff --git a/infra/src/dsl/output-generators/map-to-helm-values.ts b/infra/src/dsl/output-generators/map-to-helm-values.ts index 24c5d7672082..8e75cd861692 100644 --- a/infra/src/dsl/output-generators/map-to-helm-values.ts +++ b/infra/src/dsl/output-generators/map-to-helm-values.ts @@ -50,6 +50,7 @@ const serializeService: SerializeMethod = async ( 'application-system-form', 'github-actions-cache', 'portals-admin', + 'service-portal', 'island-ui-storybook', ] const result: HelmService = { From 60be8829ccaf895eaf75c61679718f0ab5565dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3rey=20J=C3=B3na?= Date: Thu, 30 May 2024 15:29:27 +0000 Subject: [PATCH 25/82] fix(native-app): merge notification data correctly (#15021) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/native/app/src/graphql/client.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/native/app/src/graphql/client.ts b/apps/native/app/src/graphql/client.ts index 096adb246d21..97b98e2d2f51 100644 --- a/apps/native/app/src/graphql/client.ts +++ b/apps/native/app/src/graphql/client.ts @@ -157,13 +157,7 @@ const cache = new InMemoryCache({ Query: { fields: { userNotifications: { - merge(existing, incoming) { - return { - ...existing, - ...incoming, - data: incoming.data || existing.data, - } - }, + merge: true, }, }, }, From 8d821f4ff02b33be591bae3be38db72522da1137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Thu, 30 May 2024 15:44:44 +0000 Subject: [PATCH 26/82] fix(service-portal): display bio children in user information (#14685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add bio children * feat: add bio child screen * fix:merge issues * chore: import org * fix: change path * chore: nx format:write update dirty files * Update libs/service-portal/information/src/lib/navigation.ts --------- Co-authored-by: Þorkell Máni Þorkelsson Co-authored-by: andes-it Co-authored-by: Þórður H Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/lib/nationalRegistry.service.ts | 4 + .../src/lib/resolvers/person.resolver.ts | 36 +++++ .../src/lib/shared/models/person.model.ts | 3 + .../src/lib/v3/broker.service.ts | 28 ++++ .../national-registry/src/lib/v3/mapper.ts | 44 ++--- .../v3/src/lib/nationalRegistryV3.service.ts | 4 +- .../FamilyMemberCard/FamilyMemberCard.tsx | 19 ++- .../information/src/lib/navigation.ts | 7 +- .../information/src/lib/paths.ts | 3 +- .../service-portal/information/src/module.tsx | 23 ++- .../src/screens/BioChild/BioChild.graphql | 31 ++++ .../src/screens/BioChild/BioChild.tsx | 151 ++++++++++++++++++ .../ChildCustody.graphql} | 0 .../ChildCustody.tsx} | 35 ++-- .../src/screens/UserInfo/UserInfo.tsx | 3 +- .../UserInfoOverview/UserInfoOverview.graphql | 4 + .../UserInfoOverview/UserInfoOverview.tsx | 21 ++- 17 files changed, 361 insertions(+), 55 deletions(-) create mode 100644 libs/service-portal/information/src/screens/BioChild/BioChild.graphql create mode 100644 libs/service-portal/information/src/screens/BioChild/BioChild.tsx rename libs/service-portal/information/src/screens/{Child/Child.graphql => ChildCustody/ChildCustody.graphql} (100%) rename libs/service-portal/information/src/screens/{Child/Child.tsx => ChildCustody/ChildCustody.tsx} (98%) diff --git a/libs/api/domains/national-registry/src/lib/nationalRegistry.service.ts b/libs/api/domains/national-registry/src/lib/nationalRegistry.service.ts index 011793f99400..874be95f713c 100644 --- a/libs/api/domains/national-registry/src/lib/nationalRegistry.service.ts +++ b/libs/api/domains/national-registry/src/lib/nationalRegistry.service.ts @@ -29,6 +29,10 @@ export class NationalRegistryService { return this.v3.getChildDetails(nationalId, useFakeData) } + getBiologicalChildren(nationalId: string, data?: SharedPerson) { + return this.v3.getBiologicalFamily(nationalId, data?.rawData) + } + getCustodians(nationalId: string, data?: SharedPerson) { return this.v3.getCustodians(nationalId, data?.rawData) } diff --git a/libs/api/domains/national-registry/src/lib/resolvers/person.resolver.ts b/libs/api/domains/national-registry/src/lib/resolvers/person.resolver.ts index c23510dfc7d0..0242ebbc9fac 100644 --- a/libs/api/domains/national-registry/src/lib/resolvers/person.resolver.ts +++ b/libs/api/domains/national-registry/src/lib/resolvers/person.resolver.ts @@ -101,6 +101,42 @@ export class PersonResolver { return null } + @ResolveField('biologicalChildren', () => [ChildCustody], { + nullable: true, + }) + async resolveBiologicalChildren( + @Context('req') { user }: { user: User }, + @Parent() person: SharedPerson, + @Args('childNationalId', { nullable: true }) childNationalId?: string, + ): Promise | null> { + this.auditService.audit({ + auth: user, + namespace, + action: 'resolveBiologicalChildren', + resources: user.nationalId, + }) + + if ( + !(person.nationalIdType === NationalIdType.NATIONAL_REGISTRY_NATIONAL_ID) + ) { + return null + } + + const bioChildren = await this.service.getBiologicalChildren( + person.nationalId, + person, + ) + + if (childNationalId) { + const child = (bioChildren as Array)?.find( + (c) => c.nationalId === childNationalId, + ) + return child ? [child] : null + } + + return bioChildren as Array + } + @ResolveField('childCustody', () => [ChildCustody], { nullable: true, }) diff --git a/libs/api/domains/national-registry/src/lib/shared/models/person.model.ts b/libs/api/domains/national-registry/src/lib/shared/models/person.model.ts index b1f773cc7d5a..4da174d10eae 100644 --- a/libs/api/domains/national-registry/src/lib/shared/models/person.model.ts +++ b/libs/api/domains/national-registry/src/lib/shared/models/person.model.ts @@ -37,6 +37,9 @@ export class Person extends PersonBase { @Field(() => [ChildCustody], { nullable: true }) childCustody?: Array | null + @Field(() => [ChildCustody], { nullable: true }) + biologicalChildren?: Array | null + @Field(() => Birthplace, { nullable: true }) birthplace?: Birthplace | null diff --git a/libs/api/domains/national-registry/src/lib/v3/broker.service.ts b/libs/api/domains/national-registry/src/lib/v3/broker.service.ts index 21fff5df8087..b01b1d3e870f 100644 --- a/libs/api/domains/national-registry/src/lib/v3/broker.service.ts +++ b/libs/api/domains/national-registry/src/lib/v3/broker.service.ts @@ -153,6 +153,34 @@ export class BrokerService { return data && formatCitizenship(data) } + async getBiologicalFamily( + parentNationalId: string, + rawData?: EinstaklingurDTOAllt | null, + useFakeData?: boolean, + ): Promise | null> { + const parentData = + rawData ?? + (await this.nationalRegistryV3.getAllDataIndividual( + parentNationalId, + useFakeData, + )) + + if (!parentData) { + return null + } + + const children = parentData.logforeldrar?.born ?? [] + + return children + .map((c) => formatChildCustody(c, useFakeData)) + .filter(isDefined) + .sort((a, b) => { + return ( + kennitala.info(b.nationalId).age - kennitala.info(a.nationalId).age + ) + }) + } + async getChildrenCustodyInformation( parentNationalId: string, rawData?: EinstaklingurDTOAllt | null, diff --git a/libs/api/domains/national-registry/src/lib/v3/mapper.ts b/libs/api/domains/national-registry/src/lib/v3/mapper.ts index e64e4893368a..8a15b6a009e0 100644 --- a/libs/api/domains/national-registry/src/lib/v3/mapper.ts +++ b/libs/api/domains/national-registry/src/lib/v3/mapper.ts @@ -31,11 +31,11 @@ import * as kennitala from 'kennitala' import { maskString, isDefined } from '@island.is/shared/utils' import { FamilyChild, User } from './types' -export function formatPersonDiscriminated( +export const formatPersonDiscriminated = ( individual?: EinstaklingurDTOAllt | null, nationalId?: string, useFakeData?: boolean, -): PersonV3 | null { +): PersonV3 | null => { const person = formatPerson(individual, nationalId) if (!person) { return null @@ -49,10 +49,10 @@ export function formatPersonDiscriminated( } } -export function formatChildCustody( +export const formatChildCustody = ( childCustody?: EinstaklingurDTOForsjaItem | null, useFakeData?: boolean, -): ChildCustodyV3 | null { +): ChildCustodyV3 | null => { if (!childCustody?.barnKennitala || !childCustody?.barnNafn) { return null } @@ -64,10 +64,10 @@ export function formatChildCustody( } } -export function formatPerson( +export const formatPerson = ( individual?: EinstaklingurDTOAllt | null, nationalId?: string, -): Person | null { +): Person | null => { if (individual === null || !individual?.kennitala || !individual?.nafn) { return null } @@ -105,12 +105,12 @@ export function formatPerson( } } -export function formatHousing( +export const formatHousing = ( nationalId: string, housing?: EinstaklingurDTOItarAuka | null, domicileData?: EinstaklingurDTOLoghTengsl | null, address?: EinstaklingurDTOHeimili | null, -): Housing | null { +): Housing | null => { const addressData = housing?.heimilisfang ?? address const domicileId = domicileData?.logheimilistengsl ?? housing?.logheimiliskodi @@ -140,9 +140,9 @@ export function formatHousing( } } -export function formatSpouse( +export const formatSpouse = ( spouse?: EinstaklingurDTOHju | null, -): Spouse | null { +): Spouse | null => { if (!spouse || !spouse.makiKennitala || !spouse.makiNafn) { return null } @@ -156,9 +156,9 @@ export function formatSpouse( } } -export function formatAddress( +export const formatAddress = ( address?: EinstaklingurDTOHeimili | null, -): Address | null { +): Address | null => { if (!address || !address.husHeiti || !address.poststod) { return null } @@ -172,9 +172,9 @@ export function formatAddress( } } -export function formatBirthParent( +export const formatBirthParent = ( individual?: EinstaklingurDTOLogForeldriItem | null, -): PersonBase | null { +): PersonBase | null => { if ( !individual || !individual.logForeldriKennitala || @@ -189,9 +189,9 @@ export function formatBirthParent( } } -export function formatBirthplace( +export const formatBirthplace = ( birthplace?: EinstaklingurDTOFaeding | null, -): Birthplace | null { +): Birthplace | null => { if (!birthplace || !birthplace.faedingarStadurHeiti) { return null } @@ -205,9 +205,9 @@ export function formatBirthplace( } } -export function formatCitizenship( +export const formatCitizenship = ( citizenship?: EinstaklingurDTORikisfang | null, -): Citizenship | null { +): Citizenship | null => { if (!citizenship || !citizenship.rikisfangLand) { return null } @@ -218,9 +218,9 @@ export function formatCitizenship( } } -export function formatName( +export const formatName = ( name?: EinstaklingurDTONafnAllt | null, -): Name | null { +): Name | null => { if (!name) { return null } @@ -233,10 +233,10 @@ export function formatName( } } -export function formatCustodian( +export const formatCustodian = ( custodian?: EinstaklingurDTOForsjaItem | null, childDomicileData?: EinstaklingurDTOLoghTengsl | null, -): Custodian | null { +): Custodian | null => { if ( !custodian || !custodian.forsjaAdiliKennitala || diff --git a/libs/clients/national-registry/v3/src/lib/nationalRegistryV3.service.ts b/libs/clients/national-registry/v3/src/lib/nationalRegistryV3.service.ts index a99f311b0b2c..d840bec4405d 100644 --- a/libs/clients/national-registry/v3/src/lib/nationalRegistryV3.service.ts +++ b/libs/clients/national-registry/v3/src/lib/nationalRegistryV3.service.ts @@ -40,7 +40,9 @@ export class NationalRegistryV3ClientService { : this.individualApi.midlunV1EinstaklingarNationalIdGet({ nationalId }) } - getFamily(nationalId: string): Promise { + getBiologicalFamily( + nationalId: string, + ): Promise { return this.individualApi.midlunV1EinstaklingarNationalIdLogforeldrarGet({ nationalId, }) diff --git a/libs/service-portal/information/src/components/FamilyMemberCard/FamilyMemberCard.tsx b/libs/service-portal/information/src/components/FamilyMemberCard/FamilyMemberCard.tsx index 35360199284e..e7a956a4957a 100644 --- a/libs/service-portal/information/src/components/FamilyMemberCard/FamilyMemberCard.tsx +++ b/libs/service-portal/information/src/components/FamilyMemberCard/FamilyMemberCard.tsx @@ -14,7 +14,11 @@ interface Props { type UniqueProps = | { - familyRelation?: 'child' + familyRelation?: 'custody' + baseId: string + } + | { + familyRelation?: 'bio-child' baseId: string } | { @@ -49,12 +53,23 @@ export const FamilyMemberCard: FC< path: InformationPaths.Spouse, } } + + if (familyRelation === 'custody') { + return { + label: formatMessage({ + id: 'sp.family:child', + defaultMessage: 'Barn', + }), + path: InformationPaths.ChildCustody.replace(':baseId', baseId ?? ''), + } + } + return { label: formatMessage({ id: 'sp.family:child', defaultMessage: 'Barn', }), - path: InformationPaths.Child.replace(':baseId', baseId ?? ''), + path: InformationPaths.BioChild.replace(':baseId', baseId ?? ''), } } diff --git a/libs/service-portal/information/src/lib/navigation.ts b/libs/service-portal/information/src/lib/navigation.ts index 4b1b25acd893..bf2978ecb59d 100644 --- a/libs/service-portal/information/src/lib/navigation.ts +++ b/libs/service-portal/information/src/lib/navigation.ts @@ -28,7 +28,12 @@ export const informationNavigation: PortalNavigationItem = { { name: m.familyChild, navHide: true, - path: InformationPaths.Child, + path: InformationPaths.BioChild, + }, + { + name: m.familyChild, + navHide: true, + path: InformationPaths.ChildCustody, }, ], }, diff --git a/libs/service-portal/information/src/lib/paths.ts b/libs/service-portal/information/src/lib/paths.ts index ea8887dc5b3b..bf5ae7d08aa3 100644 --- a/libs/service-portal/information/src/lib/paths.ts +++ b/libs/service-portal/information/src/lib/paths.ts @@ -4,7 +4,8 @@ export enum InformationPaths { SettingsOld = '/stillingar/minar-stillingar/', Settings = '/min-gogn/stillingar/', SettingsNotifications = '/min-gogn/stillingar/tilkynningar', - Child = '/min-gogn/yfirlit/barn/:baseId', + ChildCustody = '/min-gogn/yfirlit/barn/:baseId', + BioChild = '/min-gogn/yfirlit/fjolskylda/:baseId', Spouse = '/min-gogn/yfirlit/maki/', UserInfo = '/min-gogn/yfirlit/minar-upplysingar', Company = '/fyrirtaeki', diff --git a/libs/service-portal/information/src/module.tsx b/libs/service-portal/information/src/module.tsx index cdd9fea1ced5..6cef20c02fd5 100644 --- a/libs/service-portal/information/src/module.tsx +++ b/libs/service-portal/information/src/module.tsx @@ -14,7 +14,10 @@ const UserInfoOverview = lazy(() => import('./screens/UserInfoOverview/UserInfoOverview'), ) const UserInfo = lazy(() => import('./screens/UserInfo/UserInfo')) -const FamilyMemberChild = lazy(() => import('./screens/Child/Child')) +const FamilyMemberChildCustody = lazy(() => + import('./screens/ChildCustody/ChildCustody'), +) +const FamilyMemberBioChild = lazy(() => import('./screens/BioChild/BioChild')) const Spouse = lazy(() => import('./screens/Spouse/Spouse')) const CompanyInfo = lazy(() => import('./screens/Company/CompanyInfo')) const Notifications = lazy(() => @@ -70,6 +73,18 @@ export const informationModule: PortalModule = { enabled: userInfo.scopes.includes(ApiScope.meDetails), element: , }, + { + name: 'BioChild', + path: InformationPaths.BioChild, + enabled: userInfo.scopes.includes(ApiScope.meDetails), + element: , + }, + { + name: 'Child', + path: InformationPaths.ChildCustody, + enabled: userInfo.scopes.includes(ApiScope.meDetails), + element: , + }, { name: m.userInfo, path: InformationPaths.SettingsNotifications, @@ -77,12 +92,6 @@ export const informationModule: PortalModule = { key: 'NotificationSettings', element: , }, - { - name: 'Child', - path: InformationPaths.Child, - enabled: userInfo.scopes.includes(ApiScope.meDetails), - element: , - }, { name: 'Spouse', path: InformationPaths.Spouse, diff --git a/libs/service-portal/information/src/screens/BioChild/BioChild.graphql b/libs/service-portal/information/src/screens/BioChild/BioChild.graphql new file mode 100644 index 000000000000..4acf02c01d67 --- /dev/null +++ b/libs/service-portal/information/src/screens/BioChild/BioChild.graphql @@ -0,0 +1,31 @@ +query NationalRegistryBioChild( + $childNationalId: String + $useFakeData: Boolean +) { + nationalRegistryPerson(useFakeData: $useFakeData) { + nationalId + fullName + biologicalChildren(childNationalId: $childNationalId) { + __typename + details { + nationalId + fullName + baseId + __typename + name { + firstName + middleName + lastName + } + housing { + address { + streetAddress + } + } + birthParents { + nationalId + } + } + } + } +} diff --git a/libs/service-portal/information/src/screens/BioChild/BioChild.tsx b/libs/service-portal/information/src/screens/BioChild/BioChild.tsx new file mode 100644 index 000000000000..fa514175e3b5 --- /dev/null +++ b/libs/service-portal/information/src/screens/BioChild/BioChild.tsx @@ -0,0 +1,151 @@ +import { useParams } from 'react-router-dom' +import { useUserInfo } from '@island.is/auth/react' +import { useLocale, useNamespaces } from '@island.is/localization' +import { + formatNationalId, + UserInfoLine, + m, + IntroHeader, + THJODSKRA_SLUG, +} from '@island.is/service-portal/core' +import { defineMessage } from 'react-intl' +import { + Box, + Button, + Divider, + GridColumn, + GridRow, + Inline, + Stack, +} from '@island.is/island-ui/core' +import { formatNameBreaks } from '../../helpers/formatting' +import { spmm } from '../../lib/messages' +import { unmaskString } from '@island.is/shared/utils' +import { Problem } from '@island.is/react-spa/shared' +import { useNationalRegistryBioChildQuery } from './BioChild.generated' + +type UseParams = { + baseId: string +} + +const BioChild = () => { + useNamespaces('sp.family') + const { formatMessage } = useLocale() + const userInfo = useUserInfo() + const { baseId } = useParams() as UseParams + + const { data, loading, error } = useNationalRegistryBioChildQuery({ + variables: { + childNationalId: unmaskString(baseId, userInfo.profile.nationalId), + }, + }) + + const child = data?.nationalRegistryPerson?.biologicalChildren?.[0].details + const nationalId = child?.nationalId + + //Either the user is the child or a parent of the child being vieweds + const isChild = nationalId === userInfo.profile.nationalId + const isChildOfUser = child?.birthParents?.some( + (c) => c.nationalId === userInfo.profile.nationalId, + ) + + const isChildOrChildOfUser = isChild || isChildOfUser + const noChildFound = !loading && !isChildOrChildOfUser && !error + + return ( + <> + + + {error && !loading && } + {(!baseId || noChildFound) && ( + + )} + {!error && (loading || isChildOrChildOfUser) && ( + <> + + + + + + {!loading && !isChild && ( + + )} + + + + + + + + + + + + + + + + {child?.housing?.address?.streetAddress && ( + <> + + + + + + )} + + + + )} + + ) +} + +export default BioChild diff --git a/libs/service-portal/information/src/screens/Child/Child.graphql b/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.graphql similarity index 100% rename from libs/service-portal/information/src/screens/Child/Child.graphql rename to libs/service-portal/information/src/screens/ChildCustody/ChildCustody.graphql diff --git a/libs/service-portal/information/src/screens/Child/Child.tsx b/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx similarity index 98% rename from libs/service-portal/information/src/screens/Child/Child.tsx rename to libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx index c1a64fa78d50..7d9e9d3f874f 100644 --- a/libs/service-portal/information/src/screens/Child/Child.tsx +++ b/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx @@ -1,15 +1,4 @@ -import { useParams } from 'react-router-dom' import { useUserInfo } from '@island.is/auth/react' -import { useLocale, useNamespaces } from '@island.is/localization' -import { - formatNationalId, - UserInfoLine, - m, - IntroHeader, - THJODSKRA_SLUG, - LinkButton, -} from '@island.is/service-portal/core' -import { defineMessage } from 'react-intl' import { Box, Button, @@ -19,19 +8,30 @@ import { Inline, Stack, } from '@island.is/island-ui/core' +import { useLocale, useNamespaces } from '@island.is/localization' +import { Problem } from '@island.is/react-spa/shared' +import { + IntroHeader, + LinkButton, + THJODSKRA_SLUG, + UserInfoLine, + formatNationalId, + m, +} from '@island.is/service-portal/core' +import { unmaskString } from '@island.is/shared/utils' +import { defineMessage } from 'react-intl' +import { useParams } from 'react-router-dom' import { TwoColumnUserInfoLine } from '../../components/TwoColumnUserInfoLine/TwoColumnUserInfoLine' import { formatNameBreaks } from '../../helpers/formatting' -import { spmm, urls } from '../../lib/messages' -import { useNationalRegistryChildCustodyQuery } from './Child.generated' import { natRegGenderMessageDescriptorRecord } from '../../helpers/localizationHelpers' -import { unmaskString } from '@island.is/shared/utils' -import { Problem } from '@island.is/react-spa/shared' +import { spmm, urls } from '../../lib/messages' +import { useNationalRegistryChildCustodyQuery } from './ChildCustody.generated' type UseParams = { baseId: string } -const Child = () => { +const ChildCustody = () => { useNamespaces('sp.family') const { formatMessage } = useLocale() const userInfo = useUserInfo() @@ -44,6 +44,7 @@ const Child = () => { }) const child = data?.nationalRegistryPerson?.childCustody?.[0]?.details + const nationalId = child?.nationalId const parent1 = child?.birthParents ? child.birthParents[0] : undefined @@ -305,4 +306,4 @@ const Child = () => { ) } -export default Child +export default ChildCustody diff --git a/libs/service-portal/information/src/screens/UserInfo/UserInfo.tsx b/libs/service-portal/information/src/screens/UserInfo/UserInfo.tsx index 61dfb1b0d76f..72034f5c752f 100644 --- a/libs/service-portal/information/src/screens/UserInfo/UserInfo.tsx +++ b/libs/service-portal/information/src/screens/UserInfo/UserInfo.tsx @@ -2,7 +2,7 @@ import React from 'react' import { defineMessage } from 'react-intl' import { checkDelegation } from '@island.is/shared/utils' import { info } from 'kennitala' - +import { Problem } from '@island.is/react-spa/shared' import { Box, Divider, Stack } from '@island.is/island-ui/core' import { useLocale, useNamespaces } from '@island.is/localization' import { @@ -22,7 +22,6 @@ import { import { spmm, urls } from '../../lib/messages' import { formatAddress, formatNameBreaks } from '../../helpers/formatting' import { useNationalRegistryPersonQuery } from './UserInfo.generated' -import { Problem } from '@island.is/react-spa/shared' const SubjectInfo = () => { useNamespaces('sp.family') diff --git a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.graphql b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.graphql index 9726f4c0c9b7..a2055d4eb26a 100644 --- a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.graphql +++ b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.graphql @@ -10,5 +10,9 @@ query UserInfoOverview($useFakeData: Boolean) { nationalId fullName } + biologicalChildren { + nationalId + fullName + } } } diff --git a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx index 6ad0000c5d4e..124cd36d94ad 100644 --- a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx +++ b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx @@ -22,7 +22,13 @@ const UserInfoOverview = () => { const { data, error, loading } = useUserInfoOverviewQuery() - const { spouse, childCustody } = data?.nationalRegistryPerson || {} + const { spouse, childCustody, biologicalChildren } = + data?.nationalRegistryPerson || {} + + //Filter out children with custody + const bioChildren = biologicalChildren?.filter( + (child) => !childCustody?.some((c) => c.nationalId === child.nationalId), + ) return ( <> @@ -73,7 +79,18 @@ const UserInfoOverview = () => { baseId={ maskString(child.nationalId, userInfo.profile.nationalId) ?? '' } - familyRelation="child" + familyRelation="custody" + /> + ))} + {bioChildren?.map((child) => ( + ))} From b2d46d96b29f6221f72f67a21529bd64b0f7bf07 Mon Sep 17 00:00:00 2001 From: MargretFinnboga <62568905+MargretFinnboga@users.noreply.github.com> Date: Thu, 30 May 2024 16:00:37 +0000 Subject: [PATCH 27/82] feat(fa): Creating changebla month for financial-aid (#14974) * adding sortable feature * Revert "adding sortable feature" This reverts commit d9691c54de2c2fb244cf89e49c0bfe6cd7857603. * adding more detail for api * removing white space break just adding html element to the db * adding applied * when creating application * use applied when applied * creating modal * wokring onf rontend for update date * code review * remvoing unused css * applied month * updateing spec * update from code bunny * updating test * remvoing applied * fixing migration * test * trying to make test work * more test * trying to get create test to work * removing test to move on * using now factory lets go * testing lint --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../application/models/application.model.ts | 3 + ...28122439-update-application-add-applied.js | 48 ++++++++ .../application/application.service.ts | 4 +- .../application/factories/date.factory.ts | 1 + .../application/models/application.model.ts | 7 ++ .../modules/application/test/create.spec.ts | 37 ++++-- .../test/getCurrentApplication.spec.ts | 2 +- .../web-veita/graphql/sharedGql.ts | 3 + .../AppliedMonthModal.css.ts | 9 ++ .../AppliedMonthModal/AppliedMonthModal.tsx | 110 ++++++++++++++++++ .../components/Profile/ApplicationProfile.tsx | 29 ++++- .../web-veita/src/components/index.ts | 2 + .../shared/src/lib/interfaces.ts | 1 + 13 files changed, 240 insertions(+), 16 deletions(-) create mode 100644 apps/financial-aid/backend/migrations/20240528122439-update-application-add-applied.js create mode 100644 apps/financial-aid/backend/src/app/modules/application/factories/date.factory.ts create mode 100644 apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.css.ts create mode 100644 apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx diff --git a/apps/financial-aid/api/src/app/modules/application/models/application.model.ts b/apps/financial-aid/api/src/app/modules/application/models/application.model.ts index a5c584c9008a..6820c4ce1680 100644 --- a/apps/financial-aid/api/src/app/modules/application/models/application.model.ts +++ b/apps/financial-aid/api/src/app/modules/application/models/application.model.ts @@ -26,6 +26,9 @@ export class ApplicationModel implements Application { @Field() readonly modified!: string + @Field() + readonly applied!: string + @Field() readonly nationalId!: string diff --git a/apps/financial-aid/backend/migrations/20240528122439-update-application-add-applied.js b/apps/financial-aid/backend/migrations/20240528122439-update-application-add-applied.js new file mode 100644 index 000000000000..ebecf13be552 --- /dev/null +++ b/apps/financial-aid/backend/migrations/20240528122439-update-application-add-applied.js @@ -0,0 +1,48 @@ +'use strict' + +module.exports = { + async up(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction(async (t) => { + // Add the new column + await queryInterface.addColumn( + 'applications', + 'applied', + { + type: Sequelize.DATE, + allowNull: true, + }, + { transaction: t }, + ) + + // Update the applied column with the createdAt date + await queryInterface.sequelize.query( + ` + UPDATE applications + SET applied = created; + `, + { transaction: t }, + ) + + // Change the column to not allow null values if necessary + await queryInterface.changeColumn( + 'applications', + 'applied', + { + type: Sequelize.DATE, + allowNull: false, + }, + { transaction: t }, + ) + }) + }, + + async down(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((t) => + Promise.all([ + queryInterface.removeColumn('applications', 'applied', { + transaction: t, + }), + ]), + ) + }, +} diff --git a/apps/financial-aid/backend/src/app/modules/application/application.service.ts b/apps/financial-aid/backend/src/app/modules/application/application.service.ts index ba8d96c9f803..4c02909cf344 100644 --- a/apps/financial-aid/backend/src/app/modules/application/application.service.ts +++ b/apps/financial-aid/backend/src/app/modules/application/application.service.ts @@ -55,6 +55,7 @@ import { DeductionFactorsModel } from '../deductionFactors' import { DirectTaxPaymentService } from '../directTaxPayment' import { DirectTaxPaymentModel } from '../directTaxPayment/models' import { ChildrenModel, ChildrenService } from '../children' +import { nowFactory } from './factories/date.factory' interface Recipient { name: string @@ -146,7 +147,7 @@ export class ApplicationService { spouseNationalId: nationalId, }, ], - created: { [Op.gte]: firstDateOfMonth() }, + applied: { [Op.gte]: firstDateOfMonth() }, }, }) @@ -294,6 +295,7 @@ export class ApplicationService { const appModel = await this.applicationModel.create({ ...application, + applied: nowFactory(), nationalId: application.nationalId || user.nationalId, }) diff --git a/apps/financial-aid/backend/src/app/modules/application/factories/date.factory.ts b/apps/financial-aid/backend/src/app/modules/application/factories/date.factory.ts new file mode 100644 index 000000000000..d6805340f92e --- /dev/null +++ b/apps/financial-aid/backend/src/app/modules/application/factories/date.factory.ts @@ -0,0 +1 @@ +export const nowFactory = () => new Date() diff --git a/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts b/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts index 049dd7656769..cf12e6c028bf 100644 --- a/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts +++ b/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts @@ -49,6 +49,13 @@ export class ApplicationModel extends Model { @ApiProperty() modified: Date + @Column({ + type: DataType.DATE, + allowNull: false, + }) + @ApiProperty() + applied: Date + @Column({ type: DataType.STRING, allowNull: false, diff --git a/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts b/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts index 90509e2f2711..2fd79316df95 100644 --- a/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts +++ b/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts @@ -1,6 +1,7 @@ import { EmailService } from '@island.is/email-service' import { ApplicationState, + ChildrenAid, Employment, FamilyStatus, FileType, @@ -21,6 +22,8 @@ import { ApplicationModel } from '../models/application.model' import { createTestingApplicationModule } from './createTestingApplicationModule' import { DirectTaxPaymentService } from '../../directTaxPayment' import { ChildrenService } from '../../children' +import { nowFactory } from '../factories/date.factory' +jest.mock('../factories/date.factory') interface Then { result: ApplicationModel @@ -80,6 +83,7 @@ describe('ApplicationController - Create', () => { describe('database query', () => { let mockCreate: jest.Mock let mockFindOne: jest.Mock + const date = new Date() const user: User = { nationalId: '0000000000', @@ -121,6 +125,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } beforeEach(async () => { @@ -129,6 +135,9 @@ describe('ApplicationController - Create', () => { const mockFindApplication = mockApplicationModel.findOne as jest.Mock mockFindApplication.mockReturnValueOnce(null) + const mockToday = nowFactory as jest.Mock + mockToday.mockReturnValueOnce(date) + await givenWhenThen(user, application) }) @@ -136,6 +145,7 @@ describe('ApplicationController - Create', () => { expect(mockCreate).toHaveBeenCalledWith({ nationalId: user.nationalId, ...application, + applied: date, }) }) @@ -150,7 +160,7 @@ describe('ApplicationController - Create', () => { spouseNationalId: user.nationalId, }, ], - created: { [Op.gte]: firstDateOfMonth() }, + applied: { [Op.gte]: firstDateOfMonth() }, }, }) }) @@ -201,6 +211,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } const municipality: Municipality = { @@ -213,12 +225,14 @@ describe('ApplicationController - Create', () => { individualAid: undefined, cohabitationAid: undefined, usingNav: false, + childrenAid: ChildrenAid.NOTDEFINED, } const appModel = { id, state: application.state, created: new Date(), + applied: new Date(), email: application.email, } @@ -323,6 +337,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: null, nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } const municipality: Municipality = { @@ -335,12 +351,14 @@ describe('ApplicationController - Create', () => { individualAid: undefined, cohabitationAid: undefined, usingNav: false, + childrenAid: ChildrenAid.NOTDEFINED, } const appModel = { id, state: application.state, created: new Date(), + applied: new Date(), email: application.email, spouseEmail: application.spouseEmail, spouseName: application.spouseName, @@ -437,12 +455,15 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } const appModel = { id, state: application.state, created: new Date(), + applied: new Date(), email: application.email, } @@ -532,6 +553,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: '', spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } const user: User = { nationalId: '0000000000', @@ -542,6 +565,7 @@ describe('ApplicationController - Create', () => { id, state: application.state, created: new Date(), + applied: new Date(), email: application.email, } @@ -623,13 +647,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, - } - - const appModel = { - id, - state: application.state, - created: new Date(), - email: application.email, + children: [], + childrenComment: '', } beforeEach(async () => { @@ -687,6 +706,8 @@ describe('ApplicationController - Create', () => { applicationSystemId: '', nationalId: user.nationalId, spouseHasFetchedDirectTaxPayment: false, + children: [], + childrenComment: '', } beforeEach(async () => { diff --git a/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts b/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts index 83fb32bb64f3..9d17e9970e28 100644 --- a/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts +++ b/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts @@ -56,7 +56,7 @@ describe('ApplicationController - Get current application', () => { spouseNationalId: user.nationalId, }, ], - created: { [Op.gte]: firstDateOfMonth() }, + applied: { [Op.gte]: firstDateOfMonth() }, }, }) }) diff --git a/apps/financial-aid/web-veita/graphql/sharedGql.ts b/apps/financial-aid/web-veita/graphql/sharedGql.ts index ce29ec6a418e..7952f3ee9b6f 100644 --- a/apps/financial-aid/web-veita/graphql/sharedGql.ts +++ b/apps/financial-aid/web-veita/graphql/sharedGql.ts @@ -7,6 +7,7 @@ export const ApplicationQuery = gql` applicationSystemId nationalId created + applied modified name phoneNumber @@ -208,6 +209,7 @@ export const ApplicationEventMutation = gql` nationalId created modified + applied name phoneNumber email @@ -328,6 +330,7 @@ export const UpdateApplicationMutation = gql` nationalId created modified + applied name phoneNumber email diff --git a/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.css.ts b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.css.ts new file mode 100644 index 000000000000..120820488ccb --- /dev/null +++ b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.css.ts @@ -0,0 +1,9 @@ +import { style } from '@vanilla-extract/css' + +export const modal = style({ + display: 'block', + width: '100%', + maxWidth: '440px', + boxShadow: '0px 8px 32px rgba(0, 0, 0, 0.08)', + borderRadius: '12px', +}) diff --git a/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx new file mode 100644 index 000000000000..ea92ee0a01de --- /dev/null +++ b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx @@ -0,0 +1,110 @@ +import React from 'react' +import { ModalBase, Text, Box } from '@island.is/island-ui/core' +import format from 'date-fns/format' + +import * as styles from './AppliedMonthModal.css' +import * as modalButtonStyles from '../ModalTypes/ModalTypes.css' +import cn from 'classnames' + +import * as modalStyles from '../StateModal/StateModal.css' + +import { getMonth } from '@island.is/financial-aid/shared/lib' + +interface Props { + headline: string + isVisible: boolean + onVisibilityChange: React.Dispatch> + appliedDate: string + createdDate: string +} + +const AppliedMonthModal = ({ + headline, + isVisible, + onVisibilityChange, + appliedDate, + createdDate, +}: Props) => { + const closeModal = (): void => { + onVisibilityChange(false) + } + + const getSurroundingMonths = (createdDate: string): Date[] => { + const date = new Date(createdDate) + + if (Number.isNaN(date.getTime())) { + throw new Error('Invalid date') + } + + const year = date.getFullYear() + const month = date.getMonth() + + // Calculate the previous two months + const prevMonth1 = new Date(year, month - 1) + const prevMonth2 = new Date(year, month - 2) + + // Calculate the next month + const nextMonth = new Date(year, month + 1) + + return [prevMonth2, prevMonth1, date, nextMonth] + } + + return ( + { + if (visibility !== isVisible) { + onVisibilityChange(visibility) + } + }} + className={modalStyles.modalBase} + > + + + + + + + {headline} + + + + + + {getSurroundingMonths(createdDate).map((el) => { + const date = new Date(el) + const isActive = + date.getMonth() === new Date(appliedDate).getMonth() + + return ( + + ) + })} + + + + + + ) +} + +export default AppliedMonthModal diff --git a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx index 7a5019823f1f..fd6e08a39d35 100644 --- a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx +++ b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx @@ -28,6 +28,7 @@ import { ApplicationHeader, FilesListWithHeaderContainer, RejectionCommentModal, + AppliedMonthModal, } from '@island.is/financial-aid-web/veita/src/components' import { @@ -63,6 +64,8 @@ const ApplicationProfile = ({ applicationMunicipality, }: ApplicationProps) => { const [isStateModalVisible, setStateModalVisible] = useState(false) + const [appliedMonthModalVisible, setAppliedMonthModalVisible] = + useState(false) const [isRejectedReasonModalVisible, setRejectedReasonModalVisible] = useState(false) @@ -87,15 +90,19 @@ const ApplicationProfile = ({ const applicationInfo: ApplicationProfileInfo[] = [ { - title: 'Tímabil', - content: - getMonth(new Date(application.created).getMonth()) + - format(new Date(application.created), ' y'), + title: 'Dagsetning umsóknar', + content: format(new Date(application.created), 'dd.MM.y · kk:mm'), }, { - title: 'Sótt um', - content: format(new Date(application.created), 'dd.MM.y · kk:mm'), + title: 'Fyrir tímabilið', + content: + getMonth(new Date(application.applied).getMonth()) + + format(new Date(application.applied), ' y'), + onclick: () => { + setAppliedMonthModalVisible(true) + }, }, + aidAmount ? { title: 'Áætluð aðstoð', @@ -322,6 +329,16 @@ const ApplicationProfile = ({ }} reason={application.rejection ?? ''} /> + + { + setAppliedMonthModalVisible(isVisibleBoolean) + }} + appliedDate={application.applied} + createdDate={application.created} + /> ) } diff --git a/apps/financial-aid/web-veita/src/components/index.ts b/apps/financial-aid/web-veita/src/components/index.ts index 35a2195d5574..25d39400edad 100644 --- a/apps/financial-aid/web-veita/src/components/index.ts +++ b/apps/financial-aid/web-veita/src/components/index.ts @@ -15,6 +15,8 @@ export { default as OptionsModal } from './ModalTypes/OptionsModal' export { default as EmailFormatInputModal } from './ModalTypes/EmailFormatInputModal' export { default as AcceptModal } from './ModalTypes/AcceptModal' export { default as AidAmountModal } from './AidAmountModal/AidAmountModal' +export { default as AppliedMonthModal } from './AppliedMonthModal/AppliedMonthModal' + export { default as TableHeaders } from './TableHeaders/TableHeaders' export { default as SortableTableHeader } from './TableHeaders/SortableTableHeader' diff --git a/libs/financial-aid/shared/src/lib/interfaces.ts b/libs/financial-aid/shared/src/lib/interfaces.ts index 9af8bf2626f1..53ffd3e3d54f 100644 --- a/libs/financial-aid/shared/src/lib/interfaces.ts +++ b/libs/financial-aid/shared/src/lib/interfaces.ts @@ -333,6 +333,7 @@ export interface Application { id: string created: string modified: string + applied: string nationalId: string name: string phoneNumber?: string From 75cd251a2633241ff45d89374684bdb5996ed627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Thu, 30 May 2024 17:47:08 +0000 Subject: [PATCH 28/82] fix(documents): Document total count as number (#15027) --- libs/api/domains/documents/src/lib/documentV2.service.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libs/api/domains/documents/src/lib/documentV2.service.ts b/libs/api/domains/documents/src/lib/documentV2.service.ts index 90a2900a7670..08cf92057bef 100644 --- a/libs/api/domains/documents/src/lib/documentV2.service.ts +++ b/libs/api/domains/documents/src/lib/documentV2.service.ts @@ -109,8 +109,11 @@ export class DocumentServiceV2 { categoryId: mutableCategoryIds.join(), }) - if (!documents?.totalCount) { - throw new Error('Incomplete response') + if (typeof documents?.totalCount !== 'number') { + this.logger.warn('Document total count unavailable', { + category: LOG_CATEGORY, + totalCount: documents?.totalCount, + }) } const documentData: Array = @@ -134,7 +137,7 @@ export class DocumentServiceV2 { return { data: documentData, - totalCount: documents?.totalCount, + totalCount: documents?.totalCount ?? 0, unreadCount: documents?.unreadCount, pageInfo: { hasNextPage: false, From 223f6a2d7d568ad698b707fd9783fdb302079616 Mon Sep 17 00:00:00 2001 From: unakb Date: Fri, 31 May 2024 00:07:25 +0000 Subject: [PATCH 29/82] chore(j-s): Defenders API (#14980) * fix(j-s): Digital mailbox api config * fix(j-s): Config * fix(j-s): Added missing config value * Update judicial-system-xrd-robot-api.ts * Update app.config.ts * Update yaml * chore(j-s): Lawyers lib and controller added to digital mailbox api * Moving some files around * fix(j-s): cleanup * chore(j-s): Cleanup * import types as types * Update lawyers.service.ts * Update defender.controller.ts --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../infra/judicial-system-xrd-robot-api.ts | 1 + .../digital-mailbox-api/src/app/app.module.ts | 22 +++++--- .../cases/case.config.ts} | 4 +- .../cases/case.controller.ts} | 13 ++--- .../cases/case.service.ts} | 26 +++++---- .../cases}/models/cases.response.ts | 0 .../cases}/models/internalCases.response.ts | 0 .../modules/defenders/defender.controller.ts | 46 ++++++++++++++++ .../defenders/models/defender.response.ts | 12 +++++ charts/judicial-system/values.dev.yaml | 1 + charts/judicial-system/values.prod.yaml | 1 + charts/judicial-system/values.staging.yaml | 1 + libs/judicial-system/lawyers/.eslintrc.json | 35 ++++++++++++ libs/judicial-system/lawyers/README.md | 7 +++ libs/judicial-system/lawyers/jest.config.ts | 17 ++++++ libs/judicial-system/lawyers/project.json | 26 +++++++++ libs/judicial-system/lawyers/src/index.ts | 4 ++ .../lawyers/src/lib/lawyers.config.ts | 9 ++++ .../lawyers/src/lib/lawyers.module.ts | 7 +++ .../lawyers/src/lib/lawyers.service.ts | 54 +++++++++++++++++++ .../lawyers/src/lib/lawyers.types.ts | 35 ++++++++++++ libs/judicial-system/lawyers/tsconfig.json | 13 +++++ .../judicial-system/lawyers/tsconfig.lib.json | 12 +++++ .../lawyers/tsconfig.spec.json | 14 +++++ tsconfig.base.json | 3 ++ 25 files changed, 335 insertions(+), 28 deletions(-) rename apps/judicial-system/digital-mailbox-api/src/app/{app.config.ts => modules/cases/case.config.ts} (74%) rename apps/judicial-system/digital-mailbox-api/src/app/{app.controller.ts => modules/cases/case.controller.ts} (73%) rename apps/judicial-system/digital-mailbox-api/src/app/{app.service.ts => modules/cases/case.service.ts} (88%) rename apps/judicial-system/digital-mailbox-api/src/app/{ => modules/cases}/models/cases.response.ts (100%) rename apps/judicial-system/digital-mailbox-api/src/app/{ => modules/cases}/models/internalCases.response.ts (100%) create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/defender.controller.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/models/defender.response.ts create mode 100644 libs/judicial-system/lawyers/.eslintrc.json create mode 100644 libs/judicial-system/lawyers/README.md create mode 100644 libs/judicial-system/lawyers/jest.config.ts create mode 100644 libs/judicial-system/lawyers/project.json create mode 100644 libs/judicial-system/lawyers/src/index.ts create mode 100644 libs/judicial-system/lawyers/src/lib/lawyers.config.ts create mode 100644 libs/judicial-system/lawyers/src/lib/lawyers.module.ts create mode 100644 libs/judicial-system/lawyers/src/lib/lawyers.service.ts create mode 100644 libs/judicial-system/lawyers/src/lib/lawyers.types.ts create mode 100644 libs/judicial-system/lawyers/tsconfig.json create mode 100644 libs/judicial-system/lawyers/tsconfig.lib.json create mode 100644 libs/judicial-system/lawyers/tsconfig.spec.json diff --git a/apps/judicial-system/digital-mailbox-api/infra/judicial-system-xrd-robot-api.ts b/apps/judicial-system/digital-mailbox-api/infra/judicial-system-xrd-robot-api.ts index 22cb399a62a3..238f1658c6d2 100644 --- a/apps/judicial-system/digital-mailbox-api/infra/judicial-system-xrd-robot-api.ts +++ b/apps/judicial-system/digital-mailbox-api/infra/judicial-system-xrd-robot-api.ts @@ -21,6 +21,7 @@ export const serviceSetup = (services: { .secrets({ ERROR_EVENT_URL: '/k8s/judicial-system/ERROR_EVENT_URL', BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN', + LAWYERS_ICELAND_API_KEY: '/k8s/judicial-system/LAWYERS_ICELAND_API_KEY', }) .liveness('/liveness') .readiness('/liveness') diff --git a/apps/judicial-system/digital-mailbox-api/src/app/app.module.ts b/apps/judicial-system/digital-mailbox-api/src/app/app.module.ts index 3c93a751c7af..9ead4377172f 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/app.module.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/app.module.ts @@ -1,3 +1,4 @@ +import { CacheModule } from '@nestjs/cache-manager' import { Module } from '@nestjs/common' import { ConfigModule } from '@nestjs/config' @@ -8,23 +9,32 @@ import { AuditTrailModule, auditTrailModuleConfig, } from '@island.is/judicial-system/audit-trail' +import { + LawyersModule, + lawyersModuleConfig, +} from '@island.is/judicial-system/lawyers' import environment from './environments/environment' -import { digitalMailboxModuleConfig } from './app.config' -import { AppController } from './app.controller' -import { AppService } from './app.service' +import { caseModuleConfig } from './modules/cases/case.config' +import { CaseController } from './modules/cases/case.controller' +import { CaseService } from './modules/cases/case.service' +import { DefenderController } from './modules/defenders/defender.controller' @Module({ imports: [ AuditTrailModule, + LawyersModule, + CacheModule.register({ + ttl: 60 * 5 * 1000, // 5 minutes + }), ProblemModule.forRoot({ logAllErrors: true }), ConfigModule.forRoot({ isGlobal: true, - load: [digitalMailboxModuleConfig, auditTrailModuleConfig], + load: [caseModuleConfig, auditTrailModuleConfig, lawyersModuleConfig], }), AuthModule.register(environment.auth), ], - controllers: [AppController], - providers: [AppService], + controllers: [CaseController, DefenderController], + providers: [CaseService], }) export class AppModule {} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/app.config.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.config.ts similarity index 74% rename from apps/judicial-system/digital-mailbox-api/src/app/app.config.ts rename to apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.config.ts index b862108e2122..d31c82da563d 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/app.config.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from '@island.is/nest/config' -export const digitalMailboxModuleConfig = defineConfig({ - name: 'DigitalMailboxModule', +export const caseModuleConfig = defineConfig({ + name: 'DigitalMailboxCaseModule', load: (env) => ({ backendUrl: env.required('BACKEND_URL', 'http://localhost:3344'), secretToken: env.required( diff --git a/apps/judicial-system/digital-mailbox-api/src/app/app.controller.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts similarity index 73% rename from apps/judicial-system/digital-mailbox-api/src/app/app.controller.ts rename to apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts index beb6a8c26822..b0080f9a84ce 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/app.controller.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts @@ -1,18 +1,19 @@ import { Controller, Get, Inject, Query, UseGuards } from '@nestjs/common' -import { ApiCreatedResponse } from '@nestjs/swagger' +import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger' import type { User } from '@island.is/auth-nest-tools' import { CurrentUser, IdsUserGuard } from '@island.is/auth-nest-tools' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import { CasesResponse } from './models/cases.response' -import { AppService } from './app.service' +import { CaseService } from './case.service' @Controller('api') +@ApiTags('cases') @UseGuards(IdsUserGuard) -export class AppController { +export class CaseController { constructor( - private readonly appService: AppService, + private readonly caseService: CaseService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} @@ -21,7 +22,7 @@ export class AppController { async test(@CurrentUser() user: User): Promise { this.logger.debug('Testing connection') - return this.appService.testConnection(user.nationalId) + return this.caseService.testConnection(user.nationalId) } @Get('cases') @@ -32,6 +33,6 @@ export class AppController { ): Promise { this.logger.debug('Getting all cases') - return this.appService.getCases(user.nationalId, query?.lang) + return this.caseService.getCases(user.nationalId, query?.lang) } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/app.service.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts similarity index 88% rename from apps/judicial-system/digital-mailbox-api/src/app/app.service.ts rename to apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts index 0941a71390e4..9258fe724f37 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/app.service.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts @@ -1,6 +1,5 @@ import { BadGatewayException, Inject, Injectable } from '@nestjs/common' -import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import { type ConfigType } from '@island.is/nest/config' import { @@ -11,25 +10,16 @@ import { isCompletedCase } from '@island.is/judicial-system/types' import { CasesResponse } from './models/cases.response' import { InternalCasesResponse } from './models/internalCases.response' -import { digitalMailboxModuleConfig } from './app.config' +import { caseModuleConfig } from './case.config' @Injectable() -export class AppService { +export class CaseService { constructor( - @Inject(digitalMailboxModuleConfig.KEY) - private readonly config: ConfigType, - @Inject(LOGGER_PROVIDER) private readonly logger: Logger, + @Inject(caseModuleConfig.KEY) + private readonly config: ConfigType, private readonly auditTrailService: AuditTrailService, ) {} - private async test(nationalId: string): Promise { - return `OK ${nationalId}` - } - - async testConnection(nationalId: string): Promise { - return this.test(nationalId) - } - private format( response: InternalCasesResponse[], lang?: string, @@ -59,6 +49,14 @@ export class AppService { }) } + private async test(nationalId: string): Promise { + return `OK ${nationalId}` + } + + async testConnection(nationalId: string): Promise { + return this.test(nationalId) + } + private async getAllCases( nationalId: string, lang?: string, diff --git a/apps/judicial-system/digital-mailbox-api/src/app/models/cases.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts similarity index 100% rename from apps/judicial-system/digital-mailbox-api/src/app/models/cases.response.ts rename to apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts diff --git a/apps/judicial-system/digital-mailbox-api/src/app/models/internalCases.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts similarity index 100% rename from apps/judicial-system/digital-mailbox-api/src/app/models/internalCases.response.ts rename to apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/defender.controller.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/defender.controller.ts new file mode 100644 index 000000000000..0b9424c51aa9 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/defender.controller.ts @@ -0,0 +1,46 @@ +import { CacheInterceptor } from '@nestjs/cache-manager' +import { + Controller, + Get, + Inject, + InternalServerErrorException, + UseInterceptors, +} from '@nestjs/common' +import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger' + +import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' + +import { LawyersService } from '@island.is/judicial-system/lawyers' + +import { Defender } from './models/defender.response' + +@Controller('api') +@ApiTags('defenders') +@UseInterceptors(CacheInterceptor) +export class DefenderController { + constructor( + @Inject(LOGGER_PROVIDER) private readonly logger: Logger, + private readonly lawyersService: LawyersService, + ) {} + + @Get('defenders') + @ApiCreatedResponse({ + type: [Defender], + description: 'Retrieves a list of defenders', + }) + async getLawyers(): Promise { + try { + this.logger.debug('Retrieving lawyers from lawyer registry') + + const lawyers = await this.lawyersService.getLawyers() + return lawyers.map((lawyer) => ({ + nationalId: lawyer.SSN, + name: lawyer.Name, + practice: lawyer.Practice, + })) + } catch (error) { + this.logger.error('Failed to retrieve lawyers', error) + throw new InternalServerErrorException('Failed to retrieve lawyers') + } + } +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/models/defender.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/models/defender.response.ts new file mode 100644 index 000000000000..e6b8f357a2a1 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/defenders/models/defender.response.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger' + +export class Defender { + @ApiProperty({ type: String }) + nationalId!: string + + @ApiProperty({ type: String }) + name!: string + + @ApiProperty({ type: String }) + practice!: string +} diff --git a/charts/judicial-system/values.dev.yaml b/charts/judicial-system/values.dev.yaml index 8d670725811a..6034ba18586b 100644 --- a/charts/judicial-system/values.dev.yaml +++ b/charts/judicial-system/values.dev.yaml @@ -302,6 +302,7 @@ judicial-system-digital-mailbox-api: BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN' CONFIGCAT_SDK_KEY: '/k8s/configcat/CONFIGCAT_SDK_KEY' ERROR_EVENT_URL: '/k8s/judicial-system/ERROR_EVENT_URL' + LAWYERS_ICELAND_API_KEY: '/k8s/judicial-system/LAWYERS_ICELAND_API_KEY' securityContext: allowPrivilegeEscalation: false privileged: false diff --git a/charts/judicial-system/values.prod.yaml b/charts/judicial-system/values.prod.yaml index 2e9c2f0aadc8..e7e46e11483b 100644 --- a/charts/judicial-system/values.prod.yaml +++ b/charts/judicial-system/values.prod.yaml @@ -302,6 +302,7 @@ judicial-system-digital-mailbox-api: BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN' CONFIGCAT_SDK_KEY: '/k8s/configcat/CONFIGCAT_SDK_KEY' ERROR_EVENT_URL: '/k8s/judicial-system/ERROR_EVENT_URL' + LAWYERS_ICELAND_API_KEY: '/k8s/judicial-system/LAWYERS_ICELAND_API_KEY' securityContext: allowPrivilegeEscalation: false privileged: false diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index 3cb6162b7289..fc6073f8028c 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -302,6 +302,7 @@ judicial-system-digital-mailbox-api: BACKEND_ACCESS_TOKEN: '/k8s/judicial-system/BACKEND_ACCESS_TOKEN' CONFIGCAT_SDK_KEY: '/k8s/configcat/CONFIGCAT_SDK_KEY' ERROR_EVENT_URL: '/k8s/judicial-system/ERROR_EVENT_URL' + LAWYERS_ICELAND_API_KEY: '/k8s/judicial-system/LAWYERS_ICELAND_API_KEY' securityContext: allowPrivilegeEscalation: false privileged: false diff --git a/libs/judicial-system/lawyers/.eslintrc.json b/libs/judicial-system/lawyers/.eslintrc.json new file mode 100644 index 000000000000..eb74b2b984ef --- /dev/null +++ b/libs/judicial-system/lawyers/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../../.eslintrc.json", + "rules": { + "simple-import-sort/imports": [ + "error", + { + "groups": [ + // External imports come first. + ["^\\w", "@(?!nestjs|island\\.is)"], + // Then nestjs packages. + ["^@nestjs"], + // Then island.is packages. + ["^@island\\.is/(?!judicial-system)"], + // Then judicial-system packages. + ["^@island\\.is/judicial-system"], + // Then all other imports in this order: "../", "./", "./strings", "./css" + [ + "^\\.\\.(?!/?$)", + "^\\.\\./?$", + "^\\./(?=.*/)(?!/?$)", + "^\\.(?!/?$)", + "^\\./?$" + ] + ] + } + ] + }, + "plugins": ["simple-import-sort"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": {} }, + { "files": ["*.ts", "*.tsx"], "rules": {} }, + { "files": ["*.js", "*.jsx"], "rules": {} } + ] +} diff --git a/libs/judicial-system/lawyers/README.md b/libs/judicial-system/lawyers/README.md new file mode 100644 index 000000000000..f69715591606 --- /dev/null +++ b/libs/judicial-system/lawyers/README.md @@ -0,0 +1,7 @@ +# judicial-system-lawyers + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test judicial-system-lawyers` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/judicial-system/lawyers/jest.config.ts b/libs/judicial-system/lawyers/jest.config.ts new file mode 100644 index 000000000000..bc45b970b2f4 --- /dev/null +++ b/libs/judicial-system/lawyers/jest.config.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +export default { + preset: './jest.preset.js', + rootDir: '../../..', + roots: [__dirname], + globals: {}, + testEnvironment: 'node', + transform: { + '^.+\\.[tj]sx?$': [ + 'ts-jest', + { tsconfig: `${__dirname}/tsconfig.spec.json` }, + ], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '/coverage/libs/judicial-system/lawyers', + displayName: 'judicial-system-lawyers', +} diff --git a/libs/judicial-system/lawyers/project.json b/libs/judicial-system/lawyers/project.json new file mode 100644 index 000000000000..fc93d39dbe24 --- /dev/null +++ b/libs/judicial-system/lawyers/project.json @@ -0,0 +1,26 @@ +{ + "name": "judicial-system-lawyers", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/judicial-system/lawyers/src", + "projectType": "library", + "generators": {}, + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "options": { + "lintFilePatterns": [ + "libs/judicial-system/lawyers/**/*.{ts,tsx,js,jsx}" + ] + } + }, + "test": { + "executor": "@nx/jest:jest", + "options": { + "jestConfig": "libs/judicial-system/lawyers/jest.config.ts", + "passWithNoTests": true + }, + "outputs": ["{workspaceRoot}/coverage/libs/judicial-system/lawyers"] + } + }, + "tags": ["lib:judicial-system-api", "scope:judicial-system-api"] +} diff --git a/libs/judicial-system/lawyers/src/index.ts b/libs/judicial-system/lawyers/src/index.ts new file mode 100644 index 000000000000..09667709a13f --- /dev/null +++ b/libs/judicial-system/lawyers/src/index.ts @@ -0,0 +1,4 @@ +export { LawyersModule } from './lib/lawyers.module' +export { LawyersService } from './lib/lawyers.service' +export { lawyersModuleConfig } from './lib/lawyers.config' +export { Lawyer } from './lib/lawyers.types' diff --git a/libs/judicial-system/lawyers/src/lib/lawyers.config.ts b/libs/judicial-system/lawyers/src/lib/lawyers.config.ts new file mode 100644 index 000000000000..04c409773df4 --- /dev/null +++ b/libs/judicial-system/lawyers/src/lib/lawyers.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from '@island.is/nest/config' + +export const lawyersModuleConfig = defineConfig({ + name: 'LawyersModule', + load: (env) => ({ + lawyerRegistryAPI: 'https://lmfi.is/api', + lawyerRegistryAPIKey: env.required('LAWYERS_ICELAND_API_KEY'), + }), +}) diff --git a/libs/judicial-system/lawyers/src/lib/lawyers.module.ts b/libs/judicial-system/lawyers/src/lib/lawyers.module.ts new file mode 100644 index 000000000000..a21ea20321c9 --- /dev/null +++ b/libs/judicial-system/lawyers/src/lib/lawyers.module.ts @@ -0,0 +1,7 @@ +import { Global, Module } from '@nestjs/common' + +import { LawyersService } from './lawyers.service' + +@Global() +@Module({ providers: [LawyersService], exports: [LawyersService] }) +export class LawyersModule {} diff --git a/libs/judicial-system/lawyers/src/lib/lawyers.service.ts b/libs/judicial-system/lawyers/src/lib/lawyers.service.ts new file mode 100644 index 000000000000..bd2c9d670a84 --- /dev/null +++ b/libs/judicial-system/lawyers/src/lib/lawyers.service.ts @@ -0,0 +1,54 @@ +import { Inject, Injectable } from '@nestjs/common' + +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import type { ConfigType } from '@island.is/nest/config' + +import { lawyersModuleConfig } from './lawyers.config' +import type { Lawyer } from './lawyers.types' +@Injectable() +export class LawyersService { + constructor( + @Inject(lawyersModuleConfig.KEY) + private readonly config: ConfigType, + @Inject(LOGGER_PROVIDER) + private readonly logger: Logger, + ) {} + + async getLawyers(): Promise { + const response = await fetch(`${this.config.lawyerRegistryAPI}/lawyers`, { + headers: { + Authorization: `Basic ${this.config.lawyerRegistryAPIKey}`, + Accept: 'application/json', + }, + }) + + if (response.ok) { + return await response.json() + } + + const reason = await response.text() + this.logger.info('Failed to get lawyers from lawyer registry:', reason) + throw new Error(reason) + } + + async getLawyer(nationalId: string): Promise { + const response = await fetch( + `${this.config.lawyerRegistryAPI}/lawyer/${nationalId}`, + { + headers: { + Authorization: `Basic ${this.config.lawyerRegistryAPIKey}`, + Accept: 'application/json', + }, + }, + ) + + if (response.ok) { + return await response.json() + } + + const reason = await response.text() + this.logger.info('Failed to get lawyer from lawyer registry:', reason) + throw new Error(reason) + } +} diff --git a/libs/judicial-system/lawyers/src/lib/lawyers.types.ts b/libs/judicial-system/lawyers/src/lib/lawyers.types.ts new file mode 100644 index 000000000000..cf17d1b5ae63 --- /dev/null +++ b/libs/judicial-system/lawyers/src/lib/lawyers.types.ts @@ -0,0 +1,35 @@ +export type Lawyer = { + Id: number + Name: string + Title: string + Phone: string + Address: string + City: string + PostNumber: string + Email: string + Practice: string + Education: string + WebPage: string + CaseCategories: [] + FirstName: string + MiddleName: string + SurName: string + SSN: string + MailBox: string + Fax: string + GSM: string + HomePhone: string + DirectPhone: string + NonIcelandicPhone: string + PracticeResponsible: string + LawyerRepresentative: string + Sex: string + HdlLicense: string | null + HrlLicense: string | null + Insurance: string + Country: string + IsPracticing: boolean + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Languages: null | any + InternationConnection: string +} diff --git a/libs/judicial-system/lawyers/tsconfig.json b/libs/judicial-system/lawyers/tsconfig.json new file mode 100644 index 000000000000..667a3463d1d1 --- /dev/null +++ b/libs/judicial-system/lawyers/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/judicial-system/lawyers/tsconfig.lib.json b/libs/judicial-system/lawyers/tsconfig.lib.json new file mode 100644 index 000000000000..6bf998ac9cb3 --- /dev/null +++ b/libs/judicial-system/lawyers/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"], + "target": "es2021" + }, + "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/judicial-system/lawyers/tsconfig.spec.json b/libs/judicial-system/lawyers/tsconfig.spec.json new file mode 100644 index 000000000000..69a251f328ce --- /dev/null +++ b/libs/judicial-system/lawyers/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 0f85e58b9c43..2f0c56afbe2a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -872,6 +872,9 @@ "@island.is/judicial-system/formatters": [ "libs/judicial-system/formatters/src/index.ts" ], + "@island.is/judicial-system/lawyers": [ + "libs/judicial-system/lawyers/src/index.ts" + ], "@island.is/judicial-system/message": [ "libs/judicial-system/message/src/index.ts" ], From 8c99a2ba5c7c08486b09c31f3276d3487329f0f3 Mon Sep 17 00:00:00 2001 From: Herdis Maria Date: Fri, 31 May 2024 07:23:38 +0000 Subject: [PATCH 30/82] fix(auth-admin-web): remove delegation controls from old ids admin for client and api-scope (#14999) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Client/form/ClientCreateForm.tsx | 151 +------------- .../Resource/forms/ApiScopeCreateForm.tsx | 188 +----------------- .../modules/resources/resources.controller.ts | 6 +- libs/auth-api-lib/src/index.ts | 1 + .../lib/clients/dto/base/client-base.dto.ts | 2 +- .../src/lib/clients/dto/client-update.dto.ts | 10 +- .../src/lib/clients/dto/client.dto.ts | 11 +- .../lib/resources/dto/api-scope-create.dto.ts | 27 +++ .../src/lib/resources/resources.service.ts | 7 +- 9 files changed, 72 insertions(+), 331 deletions(-) create mode 100644 libs/auth-api-lib/src/lib/resources/dto/api-scope-create.dto.ts diff --git a/apps/auth-admin-web/components/Client/form/ClientCreateForm.tsx b/apps/auth-admin-web/components/Client/form/ClientCreateForm.tsx index f5e56ff7a53e..17871cbbbdda 100644 --- a/apps/auth-admin-web/components/Client/form/ClientCreateForm.tsx +++ b/apps/auth-admin-web/components/Client/form/ClientCreateForm.tsx @@ -712,149 +712,16 @@ const ClientCreateForm: React.FC> = (

{localization.sections['delegations'].title}

-
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
+ https://island.is/stjornbord/innskraningarkerfi +
+

diff --git a/apps/auth-admin-web/components/Resource/forms/ApiScopeCreateForm.tsx b/apps/auth-admin-web/components/Resource/forms/ApiScopeCreateForm.tsx index dde72376e27b..8db1effd7312 100644 --- a/apps/auth-admin-web/components/Resource/forms/ApiScopeCreateForm.tsx +++ b/apps/auth-admin-web/components/Resource/forms/ApiScopeCreateForm.tsx @@ -449,186 +449,16 @@ const ApiScopeCreateForm: React.FC> = (

{localization.sections['delegations'].title}

-
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
-
- - - -
- -
- - - -
+ https://island.is/stjornbord/innskraningarkerfi +
+

diff --git a/apps/services/auth/admin-api/src/app/modules/resources/resources.controller.ts b/apps/services/auth/admin-api/src/app/modules/resources/resources.controller.ts index afa315bc7653..5cbb3c41c8af 100644 --- a/apps/services/auth/admin-api/src/app/modules/resources/resources.controller.ts +++ b/apps/services/auth/admin-api/src/app/modules/resources/resources.controller.ts @@ -2,7 +2,6 @@ import { ApiResource, ApiScope, ApiScopeUserClaim, - ApiScopeDTO, IdentityResource, IdentityResourcesDTO, ResourcesService, @@ -19,6 +18,7 @@ import { PagedRowsDto, Domain, DomainDTO, + CreateApiScopeDTO, } from '@island.is/auth-api-lib' import { NoContentException } from '@island.is/nest/problem' import { @@ -434,7 +434,7 @@ export class ResourcesController { @Audit({ resources: (scope) => scope.name, }) - async createApiScope(@Body() apiScope: ApiScopeDTO): Promise { + async createApiScope(@Body() apiScope: CreateApiScopeDTO): Promise { return this.resourcesService.createApiScope(apiScope) } @@ -456,7 +456,7 @@ export class ResourcesController { @Put('api-scope/:name') @ApiOkResponse({ type: ApiScope }) async updateApiScope( - @Body() apiScope: ApiScopeDTO, + @Body() apiScope: CreateApiScopeDTO, @Param('name') name: string, @CurrentUser() user: User, ): Promise { diff --git a/libs/auth-api-lib/src/index.ts b/libs/auth-api-lib/src/index.ts index 6360687933cd..6e320235aa40 100644 --- a/libs/auth-api-lib/src/index.ts +++ b/libs/auth-api-lib/src/index.ts @@ -68,6 +68,7 @@ export * from './lib/resources/models/api-resource-scope.model' export * from './lib/resources/models/api-resource-secret.model' export * from './lib/resources/models/api-resource-user-claim.model' export * from './lib/resources/models/api-scope.model' +export * from './lib/resources/dto/api-scope-create.dto' export * from './lib/resources/models/api-scope-user-claim.model' export * from './lib/resources/models/api-scope-delegation-type.model' export * from './lib/resources/models/api-scope-group.model' diff --git a/libs/auth-api-lib/src/lib/clients/dto/base/client-base.dto.ts b/libs/auth-api-lib/src/lib/clients/dto/base/client-base.dto.ts index 0428455aef06..f6fcfd4981be 100644 --- a/libs/auth-api-lib/src/lib/clients/dto/base/client-base.dto.ts +++ b/libs/auth-api-lib/src/lib/clients/dto/base/client-base.dto.ts @@ -8,7 +8,7 @@ import { } from 'class-validator' import { ApiProperty } from '@nestjs/swagger' -export abstract class ClientBaseDTO { +export class ClientBaseDTO { @IsString() @IsNotEmpty() @ApiProperty({ diff --git a/libs/auth-api-lib/src/lib/clients/dto/client-update.dto.ts b/libs/auth-api-lib/src/lib/clients/dto/client-update.dto.ts index afda516eeb71..a4e01aac2936 100644 --- a/libs/auth-api-lib/src/lib/clients/dto/client-update.dto.ts +++ b/libs/auth-api-lib/src/lib/clients/dto/client-update.dto.ts @@ -1,3 +1,11 @@ import { ClientBaseDTO } from './base/client-base.dto' +import { OmitType } from '@nestjs/swagger' -export class ClientUpdateDTO extends ClientBaseDTO {} +export class ClientUpdateDTO extends OmitType(ClientBaseDTO, [ + 'supportedDelegationTypes', + 'supportsCustomDelegation', + 'supportsProcuringHolders', + 'supportsLegalGuardians', + 'supportsPersonalRepresentatives', + 'promptDelegations', +]) {} diff --git a/libs/auth-api-lib/src/lib/clients/dto/client.dto.ts b/libs/auth-api-lib/src/lib/clients/dto/client.dto.ts index 69dd8b88cb80..f4b07fbc04a4 100644 --- a/libs/auth-api-lib/src/lib/clients/dto/client.dto.ts +++ b/libs/auth-api-lib/src/lib/clients/dto/client.dto.ts @@ -1,8 +1,15 @@ import { IsString, IsNotEmpty } from 'class-validator' -import { ApiProperty } from '@nestjs/swagger' +import { ApiProperty, OmitType } from '@nestjs/swagger' import { ClientBaseDTO } from './base/client-base.dto' -export class ClientDTO extends ClientBaseDTO { +export class ClientDTO extends OmitType(ClientBaseDTO, [ + 'supportedDelegationTypes', + 'supportsCustomDelegation', + 'supportsProcuringHolders', + 'supportsLegalGuardians', + 'supportsPersonalRepresentatives', + 'promptDelegations', +]) { @IsNotEmpty() @IsString() @ApiProperty({ diff --git a/libs/auth-api-lib/src/lib/resources/dto/api-scope-create.dto.ts b/libs/auth-api-lib/src/lib/resources/dto/api-scope-create.dto.ts new file mode 100644 index 000000000000..a18927e7625b --- /dev/null +++ b/libs/auth-api-lib/src/lib/resources/dto/api-scope-create.dto.ts @@ -0,0 +1,27 @@ +import { ApiProperty, OmitType } from '@nestjs/swagger' +import { ApiScopeBaseDTO } from './base/api-scope-base.dto' +import { IsNotEmpty, IsString } from 'class-validator' + +export class CreateApiScopeDTO extends OmitType(ApiScopeBaseDTO, [ + 'supportedDelegationTypes', + 'grantToPersonalRepresentatives', + 'grantToProcuringHolders', + 'grantToLegalGuardians', + 'allowExplicitDelegationGrant', + 'grantToAuthenticatedUser', + 'automaticDelegationGrant', + 'alsoForDelegatedUser', +]) { + @IsString() + @IsNotEmpty() + @ApiProperty({ + example: 'set_display_name', + }) + readonly displayName!: string + + @IsString() + @ApiProperty({ + example: 'set_description', + }) + readonly description!: string +} diff --git a/libs/auth-api-lib/src/lib/resources/resources.service.ts b/libs/auth-api-lib/src/lib/resources/resources.service.ts index a69fc8b3a18b..9a582ae7fa25 100644 --- a/libs/auth-api-lib/src/lib/resources/resources.service.ts +++ b/libs/auth-api-lib/src/lib/resources/resources.service.ts @@ -36,6 +36,7 @@ import { ResourceTranslationService } from './resource-translation.service' import type { User } from '@island.is/auth-nest-tools' import type { Logger } from '@island.is/logging' import type { ConfigType } from '@island.is/nest/config' +import { CreateApiScopeDTO } from './dto/api-scope-create.dto' @Injectable() export class ResourcesService { constructor( @@ -516,7 +517,7 @@ export class ResourcesService { } /** Creates a new Api Scope */ - async createApiScope(apiScope: ApiScopeDTO): Promise { + async createApiScope(apiScope: CreateApiScopeDTO): Promise { this.logger.debug('Creating a new api scope') await this.assertSameAsGroup(apiScope) @@ -526,7 +527,7 @@ export class ResourcesService { /** Updates an existing API scope */ async updateApiScope( - apiScopeData: ApiScopeDTO, + apiScopeData: CreateApiScopeDTO, name: string, ): Promise { this.logger.debug('Updating api scope with name: ', name) @@ -959,7 +960,7 @@ export class ResourcesService { // #endregion Domain - private async assertSameAsGroup(apiScope: ApiScopeDTO) { + private async assertSameAsGroup(apiScope: CreateApiScopeDTO) { if (apiScope.groupId) { const scopeGroup = await this.apiScopeGroupModel.findByPk( apiScope.groupId, From 3c42d8216ea081044b5f2fc9265f8d29c392f033 Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Fri, 31 May 2024 10:15:15 +0000 Subject: [PATCH 31/82] fix(inheritance-report): efs updates 30/5 (#15023) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../inheritance-report.service.ts | 2 +- .../inheritance-report/utils/mappers.ts | 2 + .../fields/Overview/OverviewAssets/index.tsx | 2 +- .../src/forms/sections/deceased.ts | 15 ++++--- .../src/forms/sections/heirs.ts | 4 +- .../inheritance-report/src/lib/dataSchema.ts | 43 +++++++++++++++++-- .../inheritance-report/src/lib/messages.ts | 16 ++++--- .../src/lib/utils/calculateTotalAssets.ts | 2 +- .../src/lib/utils/helpers.ts | 10 ++--- 9 files changed, 72 insertions(+), 24 deletions(-) diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts index 9b73084d4509..bc0e5a2811ee 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts @@ -68,7 +68,7 @@ export class InheritanceReportService extends BaseTemplateApiService { return new Promise((resolve) => { this.syslumennService - .getInheritanceTax(inheritanceDate) + .getInheritanceTax(new Date()) .then((inheritanceTax) => { inheritanceReportInfo.inheritanceTax = inheritanceTax resolve() diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts index 4a154e52cb6b..082bb0f59e38 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts @@ -290,6 +290,8 @@ export const expandAnswers = ( answers?.customShare?.hasCustomSpouseSharePercentage ?? 'No', customSpouseSharePercentage: answers?.customShare?.customSpouseSharePercentage ?? '50', + deceasedWasMarried: answers?.customShare?.deceasedWasMarried ?? '', + deceasedHadAssets: answers?.customShare?.deceasedHadAssets ?? '', }, } } diff --git a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx index eb45507e36e6..0f75030c6e3a 100644 --- a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx @@ -89,7 +89,7 @@ export const OverviewAssets: FC> = ({ // Bank accounts const bankAccountsDataRow = getBankAccountsDataRow(answers) const bankAccountsDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.inventory.value')) ?? '', + String(getValueViaPath(answers, 'assets.bankAccounts.total')) ?? '', ) sections.push({ diff --git a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts index 1dd18ffe0fd0..e3b386ac889d 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts @@ -69,11 +69,13 @@ export const deceased = buildSection({ title: '', }), buildRadioField({ - id: 'deceasedWasMarried', + id: 'customShare.deceasedWasMarried', title: m.wasInCohabitation, largeButtons: false, backgroundColor: 'white', + defaultValue: '', width: 'half', + required: true, options: [ { value: YES, label: m.yes }, { value: NO, label: m.no }, @@ -85,13 +87,14 @@ export const deceased = buildSection({ title: '', }), buildRadioField({ - id: 'deceasedHadAssets', + id: 'customShare.deceasedHadAssets', title: m.hadSeparateProperty, largeButtons: false, backgroundColor: 'white', width: 'half', + required: true, condition: (answers) => - getValueViaPath(answers, 'deceasedWasMarried') === YES, + getValueViaPath(answers, 'customShare.deceasedWasMarried') === YES, options: [ { value: YES, label: m.yes }, { value: NO, label: m.no }, @@ -108,8 +111,9 @@ export const deceased = buildSection({ largeButtons: false, backgroundColor: 'white', width: 'half', + required: true, condition: (answers) => - getValueViaPath(answers, 'deceasedWasMarried') === YES, + getValueViaPath(answers, 'customShare.deceasedWasMarried') === YES, options: [ { value: YES, label: m.spouseSharePart }, { value: NO, label: m.spouseShareFull }, @@ -126,7 +130,8 @@ export const deceased = buildSection({ getValueViaPath( answers, 'customShare.hasCustomSpouseSharePercentage', - ) === YES, + ) === YES && + getValueViaPath(answers, 'customShare.deceasedWasMarried') === YES, }), ], }), diff --git a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts index 1053f617fbdf..3fac8faf7869 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts @@ -174,7 +174,7 @@ export const heirs = buildSection({ buildFileUploadField({ id: 'heirsAdditionalInfoPrivateTransferFiles', uploadAccept: '.pdf, .doc, .docx, .jpg, .jpeg, .png, .xls, .xlsx', - uploadDescription: m.fileUploadFileTypes, + uploadDescription: m.uploadPrivateTransferDescription, uploadMultiple: false, title: '', uploadHeader: '', @@ -189,7 +189,7 @@ export const heirs = buildSection({ buildFileUploadField({ id: 'heirsAdditionalInfoFilesOtherDocuments', uploadAccept: '.pdf, .doc, .docx, .jpg, .jpeg, .png, .xls, .xlsx', - uploadDescription: m.fileUploadFileTypes, + uploadDescription: m.uploadOtherDocumentsDescription, title: '', uploadHeader: '', }), diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index 3c464403435b..649d954c57c9 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -593,12 +593,48 @@ export const inheritanceReportSchema = z.object({ netPropertyForExchange: z.number(), customShare: z .object({ + deceasedWasMarried: z.string().min(1), + deceasedHadAssets: z.string().optional(), hasCustomSpouseSharePercentage: z.string().optional(), customSpouseSharePercentage: z.string().optional(), }) .refine( - ({ hasCustomSpouseSharePercentage, customSpouseSharePercentage }) => { - if (hasCustomSpouseSharePercentage === YES) { + ({ deceasedWasMarried, hasCustomSpouseSharePercentage }) => { + if (deceasedWasMarried === YES) { + return ( + hasCustomSpouseSharePercentage && + [YES, NO].includes(hasCustomSpouseSharePercentage) + ) + } + + return true + }, + { + path: ['hasCustomSpouseSharePercentage'], + }, + ) + .refine( + ({ deceasedWasMarried, deceasedHadAssets }) => { + if (deceasedWasMarried === YES) { + return deceasedHadAssets && [YES, NO].includes(deceasedHadAssets) + } + + return true + }, + { + path: ['deceasedHadAssets'], + }, + ) + .refine( + ({ + hasCustomSpouseSharePercentage, + customSpouseSharePercentage, + deceasedWasMarried, + }) => { + if ( + hasCustomSpouseSharePercentage === YES && + deceasedWasMarried === YES + ) { const val = valueToNumber(customSpouseSharePercentage) return val >= 50 && val <= 100 } @@ -609,8 +645,7 @@ export const inheritanceReportSchema = z.object({ path: ['customSpouseSharePercentage'], params: m.assetsToShareHasCustomSpousePercentageError, }, - ) - .optional(), + ), confirmAction: z.array(z.enum([YES])).length(1), }) diff --git a/libs/application/templates/inheritance-report/src/lib/messages.ts b/libs/application/templates/inheritance-report/src/lib/messages.ts index d5b8a29d4e2b..5a0ef2f34f1a 100644 --- a/libs/application/templates/inheritance-report/src/lib/messages.ts +++ b/libs/application/templates/inheritance-report/src/lib/messages.ts @@ -1399,15 +1399,21 @@ export const m = defineMessages({ defaultMessage: 'Einkaskiptagerð', description: '', }, - fileUploadFileTypes: { - id: 'ir.application:fileUploadFileTypes', + fileUploadOtherDocuments: { + id: 'ir.application:fileUploadOtherDocuments', + defaultMessage: 'Önnur fylgigögn', + description: '', + }, + uploadPrivateTransferDescription: { + id: 'ir.application:uploadPrivateTransferDescription', defaultMessage: 'Samþykktar skráargerðir eru .pdf, .doc, .docx, .jpg, .jpeg, .png, .xls og .xlsx', description: '', }, - fileUploadOtherDocuments: { - id: 'ir.application:fileUploadOtherDocuments', - defaultMessage: 'Önnur fylgigögn', + uploadOtherDocumentsDescription: { + id: 'ir.application:uploadOtherDocumentsDescription', + defaultMessage: + 'Samþykktar skráargerðir eru .pdf, .doc, .docx, .jpg, .jpeg, .png, .xls og .xlsx', description: '', }, heirShare: { diff --git a/libs/application/templates/inheritance-report/src/lib/utils/calculateTotalAssets.ts b/libs/application/templates/inheritance-report/src/lib/utils/calculateTotalAssets.ts index 25cacfbe0c17..56887e0b0122 100644 --- a/libs/application/templates/inheritance-report/src/lib/utils/calculateTotalAssets.ts +++ b/libs/application/templates/inheritance-report/src/lib/utils/calculateTotalAssets.ts @@ -18,7 +18,7 @@ export const calculateTotalAssets = (answers: FormValue): number => { const stocksTotal = getValueViaPath(answers, 'assets.stocks.total') || 0 const otherAssetsTotal = valueToNumber( - getValueViaPath(answers, 'assets.otherAssets.value') || 0, + getValueViaPath(answers, 'assets.otherAssets.total') || 0, ) const realEstateTotal = getValueViaPath(answers, 'assets.realEstate.total') || 0 diff --git a/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts b/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts index d09229d172a0..c5b5ce8dd661 100644 --- a/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts +++ b/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts @@ -97,23 +97,23 @@ export const getDeceasedWasMarriedAndHadAssets = ( export const getDeceasedHadAssets = (application: Application): boolean => application?.answers && - getValueViaPath(application.answers, 'deceasedHadAssets') === YES + getValueViaPath(application.answers, 'customShare.deceasedHadAssets') === YES export const getDeceasedWasInCohabitation = ( application: Application, ): boolean => application?.answers && - getValueViaPath(application.answers, 'deceasedWasMarried') === YES + getValueViaPath(application.answers, 'customShare.deceasedWasMarried') === YES export const hasYes = (arr?: string[]) => Array.isArray(arr) && arr.includes(YES) export const shouldShowDeceasedShareField = (answers: FormValue) => - getValueViaPath(answers, 'deceasedHadAssets') === YES && - getValueViaPath(answers, 'deceasedWasMarried') === YES + getValueViaPath(answers, 'customShare.deceasedHadAssets') === YES && + getValueViaPath(answers, 'customShare.deceasedWasMarried') === YES export const shouldShowCustomSpouseShare = (answers: FormValue) => - getValueViaPath(answers, 'deceasedWasMarried') === YES + getValueViaPath(answers, 'customShare.deceasedWasMarried') === YES export const roundedValueToNumber = (value: unknown) => Math.round(valueToNumber(value)) From 1174b71dc2cc92a5d8d82ff4f6645577093d792c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3n=20Ingi?= <42949613+joningi98@users.noreply.github.com> Date: Fri, 31 May 2024 11:10:38 +0000 Subject: [PATCH 32/82] feat(endorsement-confirmation): Endorsement confirmation email (#15007) * send email when creating list * Update email * Update libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Remove test code * Remove comment * Fix --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../generalPetitionNotification.ts | 66 +++++++++++++++++++ .../general-petition.service.ts | 10 +++ 2 files changed, 76 insertions(+) create mode 100644 libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts diff --git a/libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts b/libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts new file mode 100644 index 000000000000..ce0ddee9eb1a --- /dev/null +++ b/libs/application/template-api-modules/src/lib/modules/templates/general-petition/emailGenerators/generalPetitionNotification.ts @@ -0,0 +1,66 @@ +import { getValueViaPath } from '@island.is/application/core' +import { EmailTemplateGeneratorProps } from '../../../../types' +import { SendMailOptions } from 'nodemailer' + +type GeneralPetitionNotificationEmail = ( + props: EmailTemplateGeneratorProps, +) => SendMailOptions + +export const generalPetitionNotificationEmail: GeneralPetitionNotificationEmail = + (props) => { + const { + application, + options: { + email = { sender: 'Ísland.is', address: 'no-reply@island.is' }, + }, + } = props + + const answers = application.answers + const subject = 'Staðfesting á undirskriftalista' + const { dateFrom, dateTil } = getValueViaPath( + application.answers, + 'dates', + ) as { dateFrom: string; dateTil: string } + const applicant = application.externalData.nationalRegistry?.data as { + fullName?: string + } + if (!applicant.fullName) { + throw new Error('Failed to get full name from national registry') + } + + return { + from: { + name: email.sender, + address: email.address, + }, + to: [ + { + name: applicant.fullName as string, + address: answers.email as string, + }, + ], + subject, + template: { + title: subject, + body: [ + { + component: 'Heading', + align: 'center', + context: { copy: `Undirskriftalisti ${answers.listName}` }, + }, + { + component: 'Copy', + align: 'center', + context: { + copy: `Lýsing: ${answers.aboutList}
+ Tímabil lista: ${dateFrom} - ${dateTil}
+ Stofnandi lista: ${applicant.fullName}
+ Netfang stofnenda: ${answers.email}
+ Sími notenda: ${answers.phone}
+ Kær kveðja,
Ísland.is

`, + }, + }, + ], + }, + } + } diff --git a/libs/application/template-api-modules/src/lib/modules/templates/general-petition/general-petition.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/general-petition/general-petition.service.ts index a304c342d24c..9e5bdbaa4b74 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/general-petition/general-petition.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/general-petition/general-petition.service.ts @@ -12,6 +12,7 @@ import { AuthHeaderMiddleware } from '@island.is/auth-nest-tools' import { getValueViaPath } from '@island.is/application/core' import { BaseTemplateApiService } from '../../base-template-api.service' import { ApplicationTypes } from '@island.is/application/types' +import { generalPetitionNotificationEmail } from './emailGenerators/generalPetitionNotification' const CREATE_ENDORSEMENT_LIST_QUERY = ` mutation EndorsementSystemCreateEndorsementList($input: CreateEndorsementListDto!) { @@ -88,6 +89,15 @@ export class GeneralPetitionService extends BaseTemplateApiService { throw new Error('Failed to create endorsement list') } + await this.sharedTemplateAPIService + .sendEmail( + (props) => generalPetitionNotificationEmail(props), + application, + ) + .catch((error) => { + this.logger.error('Failed to send email', error) + }) + // This gets written to externalData under the key createEndorsementList return { id: endorsementListResponse.data?.endorsementSystemCreateEndorsementList From dc451322afde99e12ddb2c4cfc3315e3fa417702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Dvar=20Oddsson?= Date: Fri, 31 May 2024 11:50:05 +0000 Subject: [PATCH 33/82] feat(j-s): digital-mailbox-api. Get case by id (#14949) * Checkpoint * Verify token * Remove unused code * feat(j-s): Digital mailbox auth guard draft * Update app.controller.ts * feat(j-s): Passport for auth * fix(j-s) * Renamed app module * Update auth.guard.ts * audience added again * chore(j-s): User decorator for nationalid info after jwt verification * chore: nx format:write update dirty files * First draft get cases * Add models * Checkpoint * Send nationalId via POST * Use type for payload * Better error handling * Checkpoint * fix(j-s): config * Use nationalId from JWT token * Implement tags * Fix types * Checkpoint * Cleanup * Remove console.log * Fix lint * checkpoint * Checkpoint * Add defendant info * Add data to API * Add linkType email and tel * Fix types * Merge * Cleanup * Cleanup * Cleanup * Refactor * Cleanup * Error handling * case number optional * Error handling * Fix types * Refactoring * 404 if case is not found * Fix formatCase function * Cases courtCaseNumber cannot be null * Cases courtCaseNumber cannot be null * Fix interface * await res.text * await res.text * Fix codegen * Fix build * Fix build --------- Co-authored-by: unakb Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../modules/case/internalCase.controller.ts | 15 ++ .../app/modules/case/internalCase.service.ts | 31 ++- .../src/app/modules/cases/case.controller.ts | 28 ++- .../src/app/modules/cases/case.service.ts | 201 +++++++++++++++--- .../app/modules/cases/models/case.response.ts | 33 +++ .../cases/models/internalCase.response.ts | 23 ++ .../audit-trail/src/lib/auditTrail.service.ts | 3 +- libs/judicial-system/types/src/index.ts | 3 +- .../types/src/lib/defendant.ts | 18 ++ 9 files changed, 326 insertions(+), 29 deletions(-) create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts index b122cb8a7630..7df5b1887435 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts @@ -85,6 +85,21 @@ export class InternalCaseController { return this.internalCaseService.getIndictmentCases(nationalId) } + @Post('cases/indictment/:caseId') + @ApiOkResponse({ + type: Case, + description: 'Gets indictment case by id', + }) + getIndictmentCase( + @Param('caseId') caseId: string, + @Body() internalCasesDto: InternalCasesDto, + ): Promise { + this.logger.debug(`Getting indictment case ${caseId}`) + const nationalId = formatNationalId(internalCasesDto.nationalId) + + return this.internalCaseService.getIndictmentCase(caseId, nationalId) + } + @UseGuards(CaseExistsGuard) @Post( `case/:caseId/${messageEndpoint[MessageType.DELIVERY_TO_COURT_PROSECUTOR]}`, diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index 020a22acc5e8..91f73348df61 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -10,6 +10,7 @@ import { Inject, Injectable, InternalServerErrorException, + NotFoundException, } from '@nestjs/common' import { InjectConnection, InjectModel } from '@nestjs/sequelize' @@ -49,8 +50,9 @@ import { CaseEvent, EventService } from '../event' import { EventLogService } from '../event-log' import { CaseFile, FileService } from '../file' import { IndictmentCount, IndictmentCountService } from '../indictment-count' +import { Institution } from '../institution' import { PoliceDocument, PoliceDocumentType, PoliceService } from '../police' -import { UserService } from '../user' +import { User, UserService } from '../user' import { InternalCreateCaseDto } from './dto/internalCreateCase.dto' import { archiveFilter } from './filters/case.archiveFilter' import { ArchiveResponse } from './models/archive.response' @@ -1059,4 +1061,31 @@ export class InternalCaseService { }, }) } + + async getIndictmentCase( + caseId: string, + nationalId: string, + ): Promise { + const caseById = await this.caseModel.findOne({ + include: [ + { model: Defendant, as: 'defendants' }, + { model: Institution, as: 'court' }, + { model: Institution, as: 'prosecutorsOffice' }, + { model: User, as: 'judge' }, + { model: User, as: 'prosecutor' }, + ], + attributes: ['courtCaseNumber'], + where: { + type: CaseType.INDICTMENT, + id: caseId, + '$defendants.national_id$': nationalId, + }, + }) + + if (!caseById) { + throw new NotFoundException(`Case ${caseId} not found`) + } + + return caseById + } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts index b0080f9a84ce..3f6a516708d4 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts @@ -1,10 +1,18 @@ -import { Controller, Get, Inject, Query, UseGuards } from '@nestjs/common' +import { + Controller, + Get, + Inject, + Param, + Query, + UseGuards, +} from '@nestjs/common' import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger' import type { User } from '@island.is/auth-nest-tools' import { CurrentUser, IdsUserGuard } from '@island.is/auth-nest-tools' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' +import { CaseResponse } from './models/case.response' import { CasesResponse } from './models/cases.response' import { CaseService } from './case.service' @@ -26,7 +34,11 @@ export class CaseController { } @Get('cases') - @ApiCreatedResponse({ type: String, description: 'Get all cases' }) + @ApiCreatedResponse({ + type: CasesResponse, + isArray: true, + description: 'Get all cases', + }) async getAllCases( @CurrentUser() user: User, @Query() query?: { lang: string }, @@ -35,4 +47,16 @@ export class CaseController { return this.caseService.getCases(user.nationalId, query?.lang) } + + @Get('case/:caseId') + @ApiCreatedResponse({ type: CaseResponse, description: 'Get case by id' }) + async getCase( + @Param('caseId') caseId: string, + @CurrentUser() user: User, + @Query() query?: { lang: string }, + ): Promise { + this.logger.debug('Getting case by id') + + return this.caseService.getCaseById(caseId, user.nationalId, query?.lang) + } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts index 9258fe724f37..7da411be3eb3 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts @@ -1,4 +1,9 @@ -import { BadGatewayException, Inject, Injectable } from '@nestjs/common' +import { + BadGatewayException, + Inject, + Injectable, + NotFoundException, +} from '@nestjs/common' import { type ConfigType } from '@island.is/nest/config' @@ -8,7 +13,9 @@ import { } from '@island.is/judicial-system/audit-trail' import { isCompletedCase } from '@island.is/judicial-system/types' +import { CaseResponse } from './models/case.response' import { CasesResponse } from './models/cases.response' +import { InternalCaseResponse } from './models/internalCase.response' import { InternalCasesResponse } from './models/internalCases.response' import { caseModuleConfig } from './case.config' @@ -49,6 +56,89 @@ export class CaseService { }) } + private formatCase(res: InternalCaseResponse, lang?: string): CaseResponse { + const language = lang?.toLowerCase() + const defendant = res.defendants[0] + + return { + data: { + caseNumber: + language === 'en' + ? `Case number ${res.courtCaseNumber}` + : `Málsnúmer ${res.courtCaseNumber}`, + groups: [ + { + label: language === 'en' ? 'Defendant' : 'Varnaraðili', + items: [ + [language === 'en' ? 'Name' : 'Nafn', defendant.name], + [ + language === 'en' ? 'National ID' : 'Kennitala', + defendant.nationalId, + ], + [ + language === 'en' ? 'Address' : 'Heimilisfang', + defendant.address, + ], + ].map((item) => ({ + label: item[0] ?? '', + value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), + })), + }, + { + label: language === 'en' ? 'Defender' : 'Verjandi', + items: [ + [language === 'en' ? 'Name' : 'Nafn', defendant.defenderName], + [ + language === 'en' ? 'Email' : 'Netfang', + defendant.defenderEmail, + 'email', + ], + [ + language === 'en' ? 'Phone Nr.' : 'Símanúmer', + defendant.defenderPhoneNumber, + 'tel', + ], + ].map((item) => ({ + label: item[0] ?? '', + value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), + linkType: item[2] ?? undefined, + })), + }, + { + label: language === 'en' ? 'Information' : 'Málsupplýsingar', + items: [ + { + label: language === 'en' ? 'Type' : 'Tegund', + value: language === 'en' ? 'Indictment' : 'Ákæra', + }, + { + label: + language === 'en' ? 'Case number' : 'Málsnúmer héraðsdóms', + value: res.courtCaseNumber, + }, + { + label: language === 'en' ? 'Court' : 'Dómstóll', + value: res.court.name, + }, + { + label: language === 'en' ? 'Judge' : 'Dómari', + value: res.judge.name, + }, + { + label: language === 'en' ? 'Institution' : 'Embætti', + value: res.prosecutorsOffice.name, + }, + { + label: language === 'en' ? 'Prosecutor' : 'Ákærandi', + value: res.prosecutor.name, + }, + ], + }, + ], + }, + } + } + private async test(nationalId: string): Promise { return `OK ${nationalId}` } @@ -61,34 +151,84 @@ export class CaseService { nationalId: string, lang?: string, ): Promise { - return fetch(`${this.config.backendUrl}/api/internal/cases/indictments`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - authorization: `Bearer ${this.config.secretToken}`, - }, - body: JSON.stringify({ nationalId }), - }) - .then(async (res) => { - const response = await res.json() + try { + const res = await fetch( + `${this.config.backendUrl}/api/internal/cases/indictments`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + authorization: `Bearer ${this.config.secretToken}`, + }, + body: JSON.stringify({ nationalId }), + }, + ) + const response = await res.json() - if (res.ok) { - return this.format(response, lang) - } + if (!res.ok) { + throw new BadGatewayException( + response?.detail || + 'Unexpected error occurred while fetching all cases', + ) + } - if (res.status < 500) { - throw new BadGatewayException(response?.detail) - } + return this.format(response, lang) + } catch (reason) { + if (reason instanceof BadGatewayException) { + throw reason + } + + throw new BadGatewayException( + `Failed to fetch all cases: ${reason.message}`, + ) + } + } - throw response - }) - .catch((reason) => { - if (reason instanceof BadGatewayException) { - throw reason + private async getCase( + id: string, + nationalId: string, + lang?: string, + ): Promise { + try { + const res = await fetch( + `${this.config.backendUrl}/api/internal/cases/indictment/${id}`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + authorization: `Bearer ${this.config.secretToken}`, + }, + body: JSON.stringify({ nationalId }), + }, + ) + + if (!res.ok) { + if (res.status === 404) { + throw new NotFoundException(`Case ${id} not found`) } - throw new BadGatewayException(reason) - }) + const reason = await res.text() + + throw new BadGatewayException( + reason || 'Unexpected error occurred while fetching case by ID', + ) + } + + const response = await res.json() + + return this.formatCase(response, lang) + } catch (reason) { + if ( + reason instanceof BadGatewayException || + reason instanceof NotFoundException + ) { + throw reason + } + + throw new BadGatewayException( + `Failed to fetch case by id: ${reason.message}`, + ) + } } async getCases(nationalId: string, lang?: string): Promise { @@ -99,4 +239,17 @@ export class CaseService { nationalId, ) } + + async getCaseById( + id: string, + nationalId: string, + lang?: string, + ): Promise { + return this.auditTrailService.audit( + 'digital-mailbox-api', + AuditedAction.GET_INDICTMENT, + this.getCase(id, nationalId, lang), + () => id, + ) + } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts new file mode 100644 index 000000000000..921110188c86 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts @@ -0,0 +1,33 @@ +import { ApiProperty } from '@nestjs/swagger' + +class IndictmentCaseData { + @ApiProperty({ type: String }) + caseNumber!: string + + @ApiProperty({ type: Object }) + groups!: Groups[] +} + +class Groups { + @ApiProperty({ type: String }) + label!: string + + @ApiProperty({ type: Object }) + items!: Items[] +} + +class Items { + @ApiProperty({ type: String }) + label!: string + + @ApiProperty({ type: String }) + value?: string + + @ApiProperty({ type: String }) + linkType?: 'email' | 'tel' +} + +export class CaseResponse { + @ApiProperty({ type: Object }) + data!: IndictmentCaseData +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts new file mode 100644 index 000000000000..a72077190c97 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts @@ -0,0 +1,23 @@ +import { ApiProperty } from '@nestjs/swagger' + +import { Defendant, Institution, User } from '@island.is/judicial-system/types' + +export class InternalCaseResponse { + @ApiProperty({ type: String }) + courtCaseNumber!: string + + @ApiProperty({ type: Object }) + defendants!: Defendant[] + + @ApiProperty({ type: Object }) + court!: Institution + + @ApiProperty({ type: Object }) + judge!: User + + @ApiProperty({ type: Object }) + prosecutorsOffice!: Institution + + @ApiProperty({ type: Object }) + prosecutor!: User +} diff --git a/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts b/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts index cfe3b161dd05..da2e10b99704 100644 --- a/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts +++ b/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts @@ -13,8 +13,9 @@ import { auditTrailModuleConfig } from './auditTrail.config' export enum AuditedAction { LOGIN = 'LOGIN', GET_CASES = 'GET_CASES', - GET_INDICTMENTS = 'GET_INDICTMENTS', GET_CASE = 'GET_CASE', + GET_INDICTMENTS = 'GET_INDICTMENTS', + GET_INDICTMENT = 'GET_INDICTMENT', CREATE_CASE = 'CREATE_CASE', UPDATE_CASE = 'UPDATE_CASE', TRANSITION_CASE = 'TRANSITION_CASE', diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index c7b78aa76a00..4b6eb0e29d6c 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -1,9 +1,10 @@ export { Feature } from './lib/feature' export { Gender } from './lib/defendant' - +export type { Defendant } from './lib/defendant' export { InstitutionType } from './lib/institution' export { NotificationType } from './lib/notification' +export type { Institution } from './lib/institution' export { EventType } from './lib/eventLog' export { DateType } from './lib/dateLog' export { CommentType } from './lib/comment' diff --git a/libs/judicial-system/types/src/lib/defendant.ts b/libs/judicial-system/types/src/lib/defendant.ts index a6868ce68d22..49b33c5eec6a 100644 --- a/libs/judicial-system/types/src/lib/defendant.ts +++ b/libs/judicial-system/types/src/lib/defendant.ts @@ -3,3 +3,21 @@ export enum Gender { FEMALE = 'FEMALE', OTHER = 'OTHER', } + +export interface Defendant { + id: string + created: string + modified: string + caseId: string + defendantWaivesRightToCounsel: boolean + noNationalId?: boolean + nationalId?: string + name?: string + gender?: Gender + address?: string + citizenship?: string + defenderName?: string + defenderNationalId?: string + defenderEmail?: string + defenderPhoneNumber?: string +} From e9b44d9821a94782e1a2154d532ab891aad9743b Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Fri, 31 May 2024 12:19:32 +0000 Subject: [PATCH 34/82] fix(inheritance-report): Foreign bank account fix (#15036) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/fields/ReportFieldsRepeater/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx index a332fe271c74..d5e5bd55ca75 100644 --- a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx @@ -47,6 +47,7 @@ type RepeaterProps = { calcWithShareValue?: boolean hideDeceasedShare?: boolean skipPushRight?: boolean + assetKey?: string } } } @@ -56,7 +57,7 @@ const valueKeys = ['exchangeRateOrInterest', 'amount'] export const ReportFieldsRepeater: FC< React.PropsWithChildren & RepeaterProps> > = ({ application, field, errors }) => { - const { answers, externalData } = application + const { answers } = application const { id, props } = field @@ -347,7 +348,7 @@ export const ReportFieldsRepeater: FC< /> ) : field.type !== 'nationalId' && field.id === 'assetNumber' && - field.props?.assetKey === 'bankAccounts' ? ( + props?.assetKey === 'bankAccounts' ? ( Date: Fri, 31 May 2024 13:05:50 +0000 Subject: [PATCH 35/82] fix(inheritance-report): ui fix for required additional assets (#15039) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../inheritance-report/src/fields/AssetsRepeater/index.tsx | 5 +++-- .../inheritance-report/src/forms/sections/assets.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx index 0ca425e5eba4..646c4baf63ab 100644 --- a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx @@ -274,6 +274,7 @@ const FieldComponent = ({ let content = null const defaultProps = { + ...field, id: fieldName, name: fieldName, format: field.format, @@ -283,13 +284,12 @@ const FieldComponent = ({ placeholder: field.placeholder, backgroundColor: field.color ? field.color : 'blue', currency: field.currency, - required: field.required, + required: readOnly ? false : field.required, loading: fieldName === loadingFieldName, suffix: field.suffix, onChange: () => onAfterChange?.(), error: error, readOnly: readOnly, - ...field, } switch (field.id) { @@ -339,6 +339,7 @@ const FieldComponent = ({ onAfterChange={onAfterChange} readOnly={readOnly} hasError={!!error} + required={field.required && !readOnly} /> ) break diff --git a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts index ee20d38ee8fb..83ddadc81142 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts @@ -56,23 +56,27 @@ export const assets = buildSection({ title: m.assetNumber, id: 'assetNumber', placeholder: 'F1234567', + required: true, }, { title: m.assetAddress, id: 'description', backgroundColor: 'white', readOnly: true, + required: true, }, { title: m.propertyShare, id: 'share', type: 'number', suffix: '%', + required: true, }, { title: m.propertyValuation, id: 'propertyValuation', currency: true, + required: true, }, ], assetKey: 'assets', From cae44e1a20066f46b3ad6bbca41f41e07cdcc503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar=20Vestmann?= <43557895+RunarVestmann@users.noreply.github.com> Date: Fri, 31 May 2024 13:35:48 +0000 Subject: [PATCH 36/82] feat(web): Housing benefit calculator, display 5 and 6 or more household member options (#15033) * Add two more options * Add feature flag --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../HousingBenefitCalculator.tsx | 79 +++++++++---------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/apps/web/components/connected/HousingBenefitCalculator/HousingBenefitCalculator.tsx b/apps/web/components/connected/HousingBenefitCalculator/HousingBenefitCalculator.tsx index 1f00070b8afb..3217c6dde785 100644 --- a/apps/web/components/connected/HousingBenefitCalculator/HousingBenefitCalculator.tsx +++ b/apps/web/components/connected/HousingBenefitCalculator/HousingBenefitCalculator.tsx @@ -6,8 +6,8 @@ import { AlertMessage, Box, Button, - Inline, - RadioButton, + Option, + Select, Stack, Text, } from '@island.is/island-ui/core' @@ -40,7 +40,7 @@ const HousingBenefitCalculator = ({ slice }: HousingBenefitCalculatorProps) => { income: '', housingCost: '', assets: '', - householdMemberCount: 0, + householdMemberCount: 1, }) const [data, setData] = useState() const updateInputState = (key: keyof InputState, value: string | number) => { @@ -97,13 +97,31 @@ const HousingBenefitCalculator = ({ slice }: HousingBenefitCalculatorProps) => { householdMemberCount === 1 || householdMemberCount === 2 || householdMemberCount === 3 || - householdMemberCount === 4 + householdMemberCount === 4 || + householdMemberCount === 5 || + householdMemberCount === 6 ) } return Boolean(inputState[key as keyof InputState]) }) }, [inputState]) + const householdMemberOptions = useMemo[]>(() => { + const options = [ + { label: '1', value: 1 }, + { label: '2', value: 2 }, + { label: '3', value: 3 }, + { label: '4', value: 4 }, + ] + + if (slice?.configJson?.showSixOptions) { + options.push({ label: '5', value: 5 }) + options.push({ label: n('sixOrMore', '6 eða fleiri'), value: 6 }) + } + + return options + }, []) + return ( { ( - - { - onChange(1) - updateInputState('householdMemberCount', 1) - }} - checked={value === 1} - /> - { - onChange(2) - updateInputState('householdMemberCount', 2) - }} - checked={value === 2} - /> - { - onChange(3) - updateInputState('householdMemberCount', 3) - }} - checked={value === 3} - /> - { - onChange(4) - updateInputState('householdMemberCount', 4) - }} - checked={value === 4} - /> - + { - if (ev?.value) { - setSelectedYear(ev) - } - }} - value={selectedYear} - /> - - - - - )} - {!noPaymentHistory && !loading && ( - - )} + From 74e90274453d2388206a60acd46d33ad7f09c3cc Mon Sep 17 00:00:00 2001 From: MargretFinnboga <62568905+MargretFinnboga@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:12:37 +0000 Subject: [PATCH 45/82] feat(fa): Adding application event and allow to update (#15002) * adding sortable feature * Revert "adding sortable feature" This reverts commit d9691c54de2c2fb244cf89e49c0bfe6cd7857603. * adding more detail for api * removing white space break just adding html element to the db * adding applied * when creating application * use applied when applied * creating modal * wokring onf rontend for update date * code review * remvoing unused css * applied month * updateing spec * update from code bunny * updating test * remvoing applied * adding event * fixing migration * test * added application event * trying to make test work * more test * adding applied to tables not filter tables * making sure people know the changes * trying to get create test to work * removing test to move on * using now factory lets go * testing lint * when updating applied not effect what staff will take the case * updating name of month * updating import * updating admin --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../dto/updateApplication.input.ts | 6 +- ...132-application_event-add-to-event_type.js | 33 +++++++++++ .../application/application.controller.ts | 1 + .../application/dto/updateApplication.dto.ts | 7 ++- .../modules/application/test/update.spec.ts | 2 + .../web-veita/graphql/sharedGql.ts | 2 + .../ApplicationHeader/ApplicationHeader.tsx | 2 +- .../ApplicationsTable/ApplicationsTable.tsx | 2 +- .../AppliedMonthModal/AppliedMonthModal.tsx | 59 ++++++++++++++++--- .../CommentSection/CommentSection.tsx | 59 ++++++++----------- .../components/Profile/ApplicationProfile.tsx | 5 +- .../src/components/StateModal/StateModal.tsx | 3 +- .../web-veita/src/utils/navigation.ts | 10 ++-- .../src/utils/useApplicationEvent.ts | 39 ++++++++++++ .../src/utils/useApplicationState.ts | 10 ++-- libs/financial-aid/shared/src/lib/enums.ts | 2 + .../shared/src/lib/formatters.ts | 6 ++ .../shared/src/lib/interfaces.ts | 1 + 18 files changed, 191 insertions(+), 58 deletions(-) create mode 100644 apps/financial-aid/backend/migrations/20240529131132-application_event-add-to-event_type.js create mode 100644 apps/financial-aid/web-veita/src/utils/useApplicationEvent.ts diff --git a/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts b/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts index b8094e23e5f0..e3ded3984884 100644 --- a/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts +++ b/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts @@ -24,6 +24,10 @@ export class UpdateApplicationInput implements UpdateApplication { @Field(() => String) readonly event!: ApplicationEventType + @Allow() + @Field({ nullable: true }) + readonly applied?: string + @Allow() @Field({ nullable: true }) readonly rejection?: string @@ -58,7 +62,7 @@ export class UpdateApplicationInput implements UpdateApplication { @Allow() @Field({ nullable: true }) - readonly spouseHasFetchedDirectTaxPayment!: boolean + readonly spouseHasFetchedDirectTaxPayment?: boolean @Allow() @Field(() => [DirectTaxPaymentInput], { nullable: true }) diff --git a/apps/financial-aid/backend/migrations/20240529131132-application_event-add-to-event_type.js b/apps/financial-aid/backend/migrations/20240529131132-application_event-add-to-event_type.js new file mode 100644 index 000000000000..7edcca5591b0 --- /dev/null +++ b/apps/financial-aid/backend/migrations/20240529131132-application_event-add-to-event_type.js @@ -0,0 +1,33 @@ +'use strict' + +const replaceEnum = require('sequelize-replace-enum-postgres').default + +module.exports = { + up: async (queryInterface, Sequelize) => { + return replaceEnum({ + queryInterface, + tableName: 'application_events', + columnName: 'event_type', + defaultValue: 'New', + newValues: [ + 'SpouseFileUpload', + 'New', + 'InProgress', + 'DataNeeded', + 'Rejected', + 'Approved', + 'StaffComment', + 'UserComment', + 'FileUpload', + 'AssignCase', + 'DateChanged', + ], + enumName: 'enum_application_events_event_type', + }) + }, + + down: async (queryInterface, Sequelize) => { + // no need to roll back + return + }, +} diff --git a/apps/financial-aid/backend/src/app/modules/application/application.controller.ts b/apps/financial-aid/backend/src/app/modules/application/application.controller.ts index 3f15a3de9bdf..6600fb51675a 100644 --- a/apps/financial-aid/backend/src/app/modules/application/application.controller.ts +++ b/apps/financial-aid/backend/src/app/modules/application/application.controller.ts @@ -246,6 +246,7 @@ export class ApplicationController { ApplicationEventType.INPROGRESS, ApplicationEventType.ASSIGNCASE, ApplicationEventType.NEW, + ApplicationEventType.DATECHANGED, ] const applicantUpdateEvents = [ diff --git a/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts b/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts index 7d86c57379f7..03f82ebddfc2 100644 --- a/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts +++ b/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts @@ -19,13 +19,18 @@ export class UpdateApplicationDto { @IsOptional() @IsString() @ApiProperty() - readonly state: ApplicationState + readonly state?: ApplicationState @IsNotEmpty() @IsString() @ApiProperty() readonly event: ApplicationEventType + @IsOptional() + @IsString() + @ApiProperty() + readonly applied?: string + @IsOptional() @IsString() @ApiProperty() diff --git a/apps/financial-aid/backend/src/app/modules/application/test/update.spec.ts b/apps/financial-aid/backend/src/app/modules/application/test/update.spec.ts index b39f4d3679d4..a00390154dd4 100644 --- a/apps/financial-aid/backend/src/app/modules/application/test/update.spec.ts +++ b/apps/financial-aid/backend/src/app/modules/application/test/update.spec.ts @@ -316,6 +316,7 @@ describe('ApplicationController - Update', () => { ${ApplicationEventType.APPROVED} ${ApplicationEventType.STAFFCOMMENT} ${ApplicationEventType.ASSIGNCASE} + ${ApplicationEventType.DATECHANGED} ${ApplicationEventType.NEW} ${ApplicationEventType.INPROGRESS} `.describe('$event', ({ event }) => { @@ -423,6 +424,7 @@ describe('ApplicationController - Update', () => { ${ApplicationEventType.APPROVED} ${ApplicationEventType.STAFFCOMMENT} ${ApplicationEventType.ASSIGNCASE} + ${ApplicationEventType.DATECHANGED} ${ApplicationEventType.NEW} ${ApplicationEventType.INPROGRESS} `.describe('$event', ({ event }) => { diff --git a/apps/financial-aid/web-veita/graphql/sharedGql.ts b/apps/financial-aid/web-veita/graphql/sharedGql.ts index 7952f3ee9b6f..0c7cf5cf95d8 100644 --- a/apps/financial-aid/web-veita/graphql/sharedGql.ts +++ b/apps/financial-aid/web-veita/graphql/sharedGql.ts @@ -151,6 +151,7 @@ export const UpdateApplicationTableMutation = gql` email modified created + applied state staff { name @@ -179,6 +180,7 @@ export const ApplicationsQuery = gql` email modified created + applied state staff { name diff --git a/apps/financial-aid/web-veita/src/components/ApplicationHeader/ApplicationHeader.tsx b/apps/financial-aid/web-veita/src/components/ApplicationHeader/ApplicationHeader.tsx index 49402de5718e..99098905f673 100644 --- a/apps/financial-aid/web-veita/src/components/ApplicationHeader/ApplicationHeader.tsx +++ b/apps/financial-aid/web-veita/src/components/ApplicationHeader/ApplicationHeader.tsx @@ -47,10 +47,10 @@ const ApplicationHeader = ({ await changeApplicationState( application.id, + ApplicationEventType.ASSIGNCASE, application.state === ApplicationState.NEW ? ApplicationState.INPROGRESS : application.state, - ApplicationEventType.ASSIGNCASE, ) .then((updatedApplication) => { setApplication(updatedApplication) diff --git a/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx b/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx index 488baf81489b..01be5e7cc62c 100644 --- a/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx +++ b/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx @@ -145,7 +145,7 @@ const ApplicationsTable = ({ ), TextTableItem( 'default', - getMonth(new Date(item.created).getMonth()), + getMonth(new Date(item.applied).getMonth()), ), assignButton(item), ]} diff --git a/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx index ea92ee0a01de..c9611cc7bdc1 100644 --- a/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx +++ b/apps/financial-aid/web-veita/src/components/AppliedMonthModal/AppliedMonthModal.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' import { ModalBase, Text, Box } from '@island.is/island-ui/core' import format from 'date-fns/format' @@ -8,7 +8,12 @@ import cn from 'classnames' import * as modalStyles from '../StateModal/StateModal.css' -import { getMonth } from '@island.is/financial-aid/shared/lib' +import { + Application, + ApplicationEventType, + getMonth, +} from '@island.is/financial-aid/shared/lib' +import { useApplicationState } from '@island.is/financial-aid-web/veita/src/utils/useApplicationState' interface Props { headline: string @@ -16,6 +21,8 @@ interface Props { onVisibilityChange: React.Dispatch> appliedDate: string createdDate: string + applicationId: string + setApplication: React.Dispatch> } const AppliedMonthModal = ({ @@ -24,10 +31,15 @@ const AppliedMonthModal = ({ onVisibilityChange, appliedDate, createdDate, + applicationId, + setApplication, }: Props) => { const closeModal = (): void => { onVisibilityChange(false) } + const currentAppliedMonth = new Date(appliedDate).getMonth() + + const [error, setError] = useState(false) const getSurroundingMonths = (createdDate: string): Date[] => { const date = new Date(createdDate) @@ -49,6 +61,28 @@ const AppliedMonthModal = ({ return [prevMonth2, prevMonth1, date, nextMonth] } + const updateApplication = useApplicationState() + + const onClickUpdateAppliedMonth = async (newDate: Date) => { + await updateApplication( + applicationId, + ApplicationEventType.DATECHANGED, + undefined, + newDate, + undefined, + `Tímabilið var breytt frá ${getMonth(currentAppliedMonth)} í ${getMonth( + new Date(newDate).getMonth(), + )}`, + ) + .then((updatedApplication) => { + setApplication(updatedApplication) + onVisibilityChange(false) + }) + .catch(() => { + setError(true) + }) + } + return ( - {getSurroundingMonths(createdDate).map((el) => { - const date = new Date(el) - const isActive = - date.getMonth() === new Date(appliedDate).getMonth() + {getSurroundingMonths(createdDate).map((surroundingMonth) => { + const date = new Date(surroundingMonth) + const isActive = date.getMonth() === currentAppliedMonth return ( ) })} +
+ + Eitthvað misstókst, vinsamlegast reyndu aftur síðar + +
diff --git a/apps/financial-aid/web-veita/src/components/CommentSection/CommentSection.tsx b/apps/financial-aid/web-veita/src/components/CommentSection/CommentSection.tsx index cd2528ca8e32..d59e52975cc5 100644 --- a/apps/financial-aid/web-veita/src/components/CommentSection/CommentSection.tsx +++ b/apps/financial-aid/web-veita/src/components/CommentSection/CommentSection.tsx @@ -1,54 +1,47 @@ import React, { useContext, useState } from 'react' -import { useRouter } from 'next/router' - import { Box, Input, Button } from '@island.is/island-ui/core' -import { useMutation } from '@apollo/client' -import { ApplicationEventMutation } from '@island.is/financial-aid-web/veita/graphql/sharedGql' import { Application, ApplicationEventType, } from '@island.is/financial-aid/shared/lib' -import { AdminContext } from '../AdminProvider/AdminProvider' import AnimateHeight from 'react-animate-height' +import { useApplicationEvent } from '@island.is/financial-aid-web/veita/src/utils/useApplicationEvent' +import { AdminContext } from '@island.is/financial-aid-web/veita/src/components/AdminProvider/AdminProvider' interface Props { - className?: string + applicationId: string setApplication: React.Dispatch> + className?: string } -const CommentSection = ({ className, setApplication }: Props) => { - const router = useRouter() - +const CommentSection = ({ + className, + setApplication, + applicationId, +}: Props) => { const { admin } = useContext(AdminContext) + const [showInput, setShowInput] = useState(false) const [comment, setComment] = useState() - const [ - createApplicationEventMutation, - { loading: isCreatingApplicationEvent }, - ] = useMutation(ApplicationEventMutation) + const { isCreatingApplicationEvent, creatApplicationEvent } = + useApplicationEvent() - const saveStaffComment = async (staffComment: string | undefined) => { - if (staffComment) { - const { data } = await createApplicationEventMutation({ - variables: { - input: { - applicationId: router.query.id, - comment: staffComment, - eventType: ApplicationEventType.STAFFCOMMENT, - staffNationalId: admin?.nationalId, - staffName: admin?.name, - }, - }, - }) + const onClickComment = async () => { + const updatedApplication = await creatApplicationEvent( + applicationId, + ApplicationEventType.STAFFCOMMENT, + admin?.nationalId, + admin?.name, + comment, + ) - if (data) { - setApplication(data.createApplicationEvent) - setComment('') - setShowInput(false) - } + if (updatedApplication) { + setApplication(updatedApplication) + setComment('') + setShowInput(false) } } @@ -84,9 +77,7 @@ const CommentSection = ({ className, setApplication }: Props) => { icon="checkmark" size="small" iconType="outline" - onClick={() => { - saveStaffComment(comment) - }} + onClick={onClickComment} disabled={isCreatingApplicationEvent} > Vista athugasemd diff --git a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx index fd6e08a39d35..c3634a406aa1 100644 --- a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx +++ b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from 'react' +import React, { useState, useMemo, useContext } from 'react' import cn from 'classnames' import format from 'date-fns/format' @@ -281,6 +281,7 @@ const ApplicationProfile = ({ {!isPrint && ( @@ -338,6 +339,8 @@ const ApplicationProfile = ({ }} appliedDate={application.applied} createdDate={application.created} + applicationId={application.id} + setApplication={setApplication} /> ) diff --git a/apps/financial-aid/web-veita/src/components/StateModal/StateModal.tsx b/apps/financial-aid/web-veita/src/components/StateModal/StateModal.tsx index ef36961a82f3..37039684f873 100644 --- a/apps/financial-aid/web-veita/src/components/StateModal/StateModal.tsx +++ b/apps/financial-aid/web-veita/src/components/StateModal/StateModal.tsx @@ -66,8 +66,9 @@ const StateModal = ({ await changeApplicationState( applicationId, - state, eventTypeFromApplicationState[state], + state, + undefined, rejection, comment, amount, diff --git a/apps/financial-aid/web-veita/src/utils/navigation.ts b/apps/financial-aid/web-veita/src/utils/navigation.ts index 85738753fecd..9b43b783cbff 100644 --- a/apps/financial-aid/web-veita/src/utils/navigation.ts +++ b/apps/financial-aid/web-veita/src/utils/navigation.ts @@ -13,10 +13,10 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Tími án umsjár', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.CREATED }, + { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIED }, { title: 'Umsjá', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], - defaultHeaderSort: ApplicationHeaderSortByEnum.CREATED, + defaultHeaderSort: ApplicationHeaderSortByEnum.APPLIED, }, { group: 'Mitt', @@ -27,7 +27,7 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Síðast uppfært', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.CREATED }, + { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIED }, { title: 'Unnið af', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], defaultHeaderSort: ApplicationHeaderSortByEnum.MODIFIED, @@ -44,7 +44,7 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Úrlausnartími', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.CREATED }, + { title: 'Sótt um', sortBy: ApplicationHeaderSortByEnum.CREATED }, { title: 'Unnið af', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], defaultHeaderSort: ApplicationHeaderSortByEnum.MODIFIED, @@ -60,7 +60,7 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Úrlausnartími', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.CREATED }, + { title: 'Sótt um', sortBy: ApplicationHeaderSortByEnum.CREATED }, { title: 'Unnið af', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], defaultHeaderSort: ApplicationHeaderSortByEnum.MODIFIED, diff --git a/apps/financial-aid/web-veita/src/utils/useApplicationEvent.ts b/apps/financial-aid/web-veita/src/utils/useApplicationEvent.ts new file mode 100644 index 000000000000..437c6c0d1d8b --- /dev/null +++ b/apps/financial-aid/web-veita/src/utils/useApplicationEvent.ts @@ -0,0 +1,39 @@ +import { useMutation } from '@apollo/client' +import { ApplicationEventType } from '@island.is/financial-aid/shared/lib' +import { ApplicationEventMutation } from '@island.is/financial-aid-web/veita/graphql/sharedGql' + +export const useApplicationEvent = () => { + const [ + createApplicationEventMutation, + { loading: isCreatingApplicationEvent }, + ] = useMutation(ApplicationEventMutation) + + const creatApplicationEvent = async ( + applicationId: string, + eventType: ApplicationEventType, + staffNationalId?: string, + staffName?: string, + staffComment?: string, + ) => { + const { data } = await createApplicationEventMutation({ + variables: { + input: { + applicationId: applicationId, + comment: staffComment, + eventType: eventType, + staffNationalId: staffNationalId, + staffName: staffName, + }, + }, + }) + + if (data) { + return data.createApplicationEvent + } + } + + return { + isCreatingApplicationEvent, + creatApplicationEvent, + } +} diff --git a/apps/financial-aid/web-veita/src/utils/useApplicationState.ts b/apps/financial-aid/web-veita/src/utils/useApplicationState.ts index c279b4dc4a91..f0e2d54385b2 100644 --- a/apps/financial-aid/web-veita/src/utils/useApplicationState.ts +++ b/apps/financial-aid/web-veita/src/utils/useApplicationState.ts @@ -34,10 +34,11 @@ export const useApplicationState = () => { } } - const changeApplicationState = async ( + const updateApplication = async ( applicationId: string, - state: ApplicationState, event: ApplicationEventType, + state?: ApplicationState, + applied?: Date, rejection?: string, comment?: string, amount?: Amount, @@ -48,9 +49,10 @@ export const useApplicationState = () => { input: { id: applicationId, state, + applied, rejection, comment, - staffId: admin?.staff?.id, + staffId: applied ? undefined : admin?.staff?.id, event, amount, }, @@ -64,5 +66,5 @@ export const useApplicationState = () => { } } - return changeApplicationState + return updateApplication } diff --git a/libs/financial-aid/shared/src/lib/enums.ts b/libs/financial-aid/shared/src/lib/enums.ts index 4e60bd7af5a7..775cdb0f96e4 100644 --- a/libs/financial-aid/shared/src/lib/enums.ts +++ b/libs/financial-aid/shared/src/lib/enums.ts @@ -47,6 +47,7 @@ export enum ApplicationHeaderSortByEnum { MODIFIED = 'modified', CREATED = 'created', STAFF = 'staff', + APPLIED = 'applied', } export enum ApplicationStateUrl { @@ -67,6 +68,7 @@ export enum ApplicationEventType { FILEUPLOAD = 'FileUpload', SPOUSEFILEUPLOAD = 'SpouseFileUpload', ASSIGNCASE = 'AssignCase', + DATECHANGED = 'DateChanged', } export enum FileType { diff --git a/libs/financial-aid/shared/src/lib/formatters.ts b/libs/financial-aid/shared/src/lib/formatters.ts index b83fa5ed5a39..d212246c2932 100644 --- a/libs/financial-aid/shared/src/lib/formatters.ts +++ b/libs/financial-aid/shared/src/lib/formatters.ts @@ -138,6 +138,12 @@ export const getEventData = ( text: 'tók að sér málið', prefix: event.staffName ?? 'Starfsmaður', } + case ApplicationEventType.DATECHANGED: + return { + header: 'Tímabil umsóknar uppfærð', + text: 'uppfærði', + prefix: event.staffName ?? 'Starfsmaður', + } } } diff --git a/libs/financial-aid/shared/src/lib/interfaces.ts b/libs/financial-aid/shared/src/lib/interfaces.ts index 53ffd3e3d54f..f707e73f8778 100644 --- a/libs/financial-aid/shared/src/lib/interfaces.ts +++ b/libs/financial-aid/shared/src/lib/interfaces.ts @@ -130,6 +130,7 @@ export interface Address { } export interface UpdateApplication { + applied?: string state?: ApplicationState event: ApplicationEventType rejection?: string From a831ebe014e5aa306727491c81f02e50021bd08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Mon, 3 Jun 2024 11:45:09 +0000 Subject: [PATCH 46/82] fix(j-s): Routing (#15049) * Fixes routing * Updates comments --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Indictments/Overview/Overview.strings.ts | 23 --- .../Court/Indictments/Overview/Overview.tsx | 117 +++------------ .../web/src/routes/Defender/CaseOverview.tsx | 4 +- .../web/src/utils/hooks/useCaseList/index.tsx | 95 +++++++----- libs/judicial-system/consts/src/lib/consts.ts | 140 +++++++++--------- 5 files changed, 155 insertions(+), 224 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts index 86819bf38a17..b479674bf746 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.strings.ts @@ -7,32 +7,9 @@ export const strings = defineMessages({ description: 'Notaður sem titill á yfirliti ákæru þegar máli er ekki lokið.', }, - completedTitle: { - id: 'judicial.system.core:indictment_overview.completed_title', - defaultMessage: 'Máli lokið', - description: 'Notaður sem titill á yfirliti ákæru þegar máli er lokið.', - }, returnIndictmentButtonText: { id: 'judicial.system.core:indictment_overview.return_indictment_button_text', defaultMessage: 'Endursenda', description: 'Notaður sem texti á takka til að endursenda ákæru.', }, - sendToPublicProsecutorModalTitle: { - id: 'judicial.system.core:indictment_overview.send_to_public_prosecutor_modal_title', - defaultMessage: 'Mál hefur verið sent til Ríkissaksóknara', - description: - 'Notaður sem titill á staðfestingarglugga um að mál hafi verið sent til Ríkissaksóknara.', - }, - sendToPublicProsecutorModalText: { - id: 'judicial.system.core:indictment_overview.send_to_public_prosecutor_modal_text', - defaultMessage: 'Gögn hafa verið send til Ríkissaksóknara til yfirlesturs', - description: - 'Notaður sem texti í staðfestingarglugga um að mál hafi verið sent til Ríkissaksóknara.', - }, - sendToPublicProsecutorModalNextButtonText: { - id: 'judicial.system.core:indictment_overview.send_to_public_prosecutor_modal_next_button_text', - defaultMessage: 'Senda til ákæruvalds', - description: - 'Notaður sem texti á takka í staðfestingarglugga um að mál hafi verið sent til Ríkissaksóknara.', - }, }) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx index d47a9bace956..2e67664769a1 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Overview/Overview.tsx @@ -2,9 +2,9 @@ import React, { useCallback, useContext, useState } from 'react' import { useIntl } from 'react-intl' import { useRouter } from 'next/router' -import { Box, toast } from '@island.is/island-ui/core' +import { Box } from '@island.is/island-ui/core' import * as constants from '@island.is/judicial-system/consts' -import { core, errors, titles } from '@island.is/judicial-system-web/messages' +import { core, titles } from '@island.is/judicial-system-web/messages' import { CourtCaseInfo, FormContentContainer, @@ -14,15 +14,12 @@ import { IndictmentsLawsBrokenAccordionItem, InfoCardActiveIndictment, InfoCardCaseScheduledIndictment, - InfoCardClosedIndictment, - Modal, PageHeader, PageLayout, PageTitle, useIndictmentsLawsBroken, } from '@island.is/judicial-system-web/src/components' import { CaseState } from '@island.is/judicial-system-web/src/graphql/schema' -import { useDefendants } from '@island.is/judicial-system-web/src/utils/hooks' import ReturnIndictmentModal from '../ReturnIndictmentCaseModal/ReturnIndictmentCaseModal' import { strings } from './Overview.strings' @@ -33,14 +30,10 @@ const IndictmentOverview = () => { useContext(FormContext) const { formatMessage } = useIntl() const lawsBroken = useIndictmentsLawsBroken(workingCase) - const { updateDefendant } = useDefendants() - const [modalVisible, setModalVisible] = useState< - 'RETURN_INDICTMENT' | 'SEND_TO_PUBLIC_PROSECUTOR' - >() + const [modalVisible, setModalVisible] = useState<'RETURN_INDICTMENT'>() const caseHasBeenReceivedByCourt = workingCase.state === CaseState.RECEIVED const latestDate = workingCase.courtDate ?? workingCase.arraignmentDate - const caseIsClosed = workingCase.state === CaseState.COMPLETED const handleNavigationTo = useCallback( (destination: string) => router.push(`${destination}/${workingCase.id}`), @@ -55,21 +48,9 @@ const IndictmentOverview = () => { isValid={true} onNavigationTo={handleNavigationTo} > - + - - {caseIsClosed - ? formatMessage(strings.completedTitle) - : formatMessage(strings.inProgressTitle)} - + {formatMessage(strings.inProgressTitle)} {caseHasBeenReceivedByCourt && workingCase.court && latestDate?.date && ( @@ -84,11 +65,7 @@ const IndictmentOverview = () => { )} - {caseIsClosed ? ( - - ) : ( - - )} + {lawsBroken.size > 0 && ( @@ -96,66 +73,28 @@ const IndictmentOverview = () => { )} {workingCase.caseFiles && ( - + )} - {caseIsClosed && ( - - { - const promises = workingCase.defendants - ? workingCase.defendants.map(async (defendant) => { - const updatedDefendant = await updateDefendant({ - caseId: workingCase.id, - defendantId: defendant.id, - serviceRequirement: defendant.serviceRequirement, - }) - - return updatedDefendant - }) - : [] - - const allDefendantsUpdated = await Promise.all(promises) - - if (allDefendantsUpdated.length > 0) { - setModalVisible('SEND_TO_PUBLIC_PROSECUTOR') - } else { - toast.error(formatMessage(errors.updateDefendant)) - } - }} - nextButtonText={formatMessage( - strings.sendToPublicProsecutorModalNextButtonText, - )} - nextIsDisabled={workingCase.defendants?.some( - (defendant) => !defendant.serviceRequirement, - )} - /> - - )} - {!caseIsClosed && ( - - - handleNavigationTo( - constants.INDICTMENTS_RECEPTION_AND_ASSIGNMENT_ROUTE, - ) - } - nextButtonText={formatMessage(core.continue)} - actionButtonText={formatMessage(strings.returnIndictmentButtonText)} - actionButtonColorScheme={'destructive'} - actionButtonIsDisabled={!workingCase.courtCaseNumber} - onActionButtonClick={() => setModalVisible('RETURN_INDICTMENT')} - /> - - )} + + + handleNavigationTo( + constants.INDICTMENTS_RECEPTION_AND_ASSIGNMENT_ROUTE, + ) + } + nextButtonText={formatMessage(core.continue)} + actionButtonText={formatMessage(strings.returnIndictmentButtonText)} + actionButtonColorScheme={'destructive'} + actionButtonIsDisabled={!caseHasBeenReceivedByCourt} + onActionButtonClick={() => setModalVisible('RETURN_INDICTMENT')} + /> + {modalVisible === 'RETURN_INDICTMENT' && ( { onComplete={() => router.push(constants.CASES_ROUTE)} /> )} - {modalVisible === 'SEND_TO_PUBLIC_PROSECUTOR' && ( - setModalVisible(undefined)} - /> - )} ) } diff --git a/apps/judicial-system/web/src/routes/Defender/CaseOverview.tsx b/apps/judicial-system/web/src/routes/Defender/CaseOverview.tsx index 3752308f7c7e..4fcc37593d60 100644 --- a/apps/judicial-system/web/src/routes/Defender/CaseOverview.tsx +++ b/apps/judicial-system/web/src/routes/Defender/CaseOverview.tsx @@ -364,7 +364,9 @@ export const CaseOverview: React.FC> = () => { strings.confirmAppealAfterDeadlineModalSecondaryButtonText, )} onPrimaryButtonClick={() => { - router.push(`${constants.APPEAL_ROUTE}/${workingCase.id}`) + router.push( + `${constants.DEFENDER_APPEAL_ROUTE}/${workingCase.id}`, + ) }} onSecondaryButtonClick={() => { setModalVisible('NoModal') diff --git a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx index 7fa6495fb7f3..edd04e4b7511 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx +++ b/apps/judicial-system/web/src/utils/hooks/useCaseList/index.tsx @@ -14,9 +14,9 @@ import { isCourtOfAppealsUser, isDefenceUser, isDistrictCourtUser, - isIndictmentCase, isInvestigationCase, isPublicProsecutorUser, + isRequestCase, isRestrictionCase, isTrafficViolationCase, } from '@island.is/judicial-system/types' @@ -77,57 +77,78 @@ const useCaseList = () => { const isTrafficViolation = isTrafficViolationCase(caseToOpen) if (isDefenceUser(user)) { - if (isIndictmentCase(caseToOpen.type)) { - routeTo = DEFENDER_INDICTMENT_ROUTE - } else { + if (isRequestCase(caseToOpen.type)) { routeTo = DEFENDER_ROUTE + } else { + routeTo = DEFENDER_INDICTMENT_ROUTE } } else if (isPublicProsecutorUser(user)) { + // Public prosecutor users can only see completed indictments routeTo = constants.PUBLIC_PROSECUTOR_STAFF_INDICTMENT_OVERVIEW_ROUTE + } else if (isCourtOfAppealsUser(user)) { + // Court of appeals users can only see appealed request cases + if (caseToOpen.appealState === CaseAppealState.COMPLETED) { + routeTo = constants.COURT_OF_APPEAL_RESULT_ROUTE + } else { + routeTo = constants.COURT_OF_APPEAL_OVERVIEW_ROUTE + } } else if (isDistrictCourtUser(user)) { if (isRestrictionCase(caseToOpen.type)) { - routeTo = findFirstInvalidStep( - constants.courtRestrictionCasesRoutes, - caseToOpen, - ) + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE + } else { + routeTo = findFirstInvalidStep( + constants.courtRestrictionCasesRoutes, + caseToOpen, + ) + } } else if (isInvestigationCase(caseToOpen.type)) { - routeTo = findFirstInvalidStep( - constants.courtInvestigationCasesRoutes, - caseToOpen, - ) - } else { - // Route to Indictment Overview section since it always a valid step and - // would be skipped if we route to the last valid step - routeTo = constants.INDICTMENTS_COURT_OVERVIEW_ROUTE - } - } else if (isCompletedCase(caseToOpen.state)) { - if (isIndictmentCase(caseToOpen.type)) { - routeTo = constants.CLOSED_INDICTMENT_OVERVIEW_ROUTE - } else if (isCourtOfAppealsUser(user)) { - if (caseToOpen.appealState === CaseAppealState.COMPLETED) { - routeTo = constants.COURT_OF_APPEAL_RESULT_ROUTE + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE } else { - routeTo = constants.COURT_OF_APPEAL_OVERVIEW_ROUTE + routeTo = findFirstInvalidStep( + constants.courtInvestigationCasesRoutes, + caseToOpen, + ) } } else { - routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.INDICTMENTS_COMPLETED_ROUTE + } else { + // Route to Indictment Overview section since it always a valid step and + // would be skipped if we route to the last valid step + routeTo = constants.INDICTMENTS_COURT_OVERVIEW_ROUTE + } } } else { + // The user is a prosecution user if (isRestrictionCase(caseToOpen.type)) { - routeTo = findFirstInvalidStep( - constants.prosecutorRestrictionCasesRoutes, - caseToOpen, - ) + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE + } else { + routeTo = findFirstInvalidStep( + constants.prosecutorRestrictionCasesRoutes, + caseToOpen, + ) + } } else if (isInvestigationCase(caseToOpen.type)) { - routeTo = findFirstInvalidStep( - constants.prosecutorInvestigationCasesRoutes, - caseToOpen, - ) + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.SIGNED_VERDICT_OVERVIEW_ROUTE + } else { + routeTo = findFirstInvalidStep( + constants.prosecutorInvestigationCasesRoutes, + caseToOpen, + ) + } } else { - routeTo = findFirstInvalidStep( - constants.prosecutorIndictmentRoutes(isTrafficViolation), - caseToOpen, - ) + if (isCompletedCase(caseToOpen.state)) { + routeTo = constants.CLOSED_INDICTMENT_OVERVIEW_ROUTE + } else { + routeTo = findFirstInvalidStep( + constants.prosecutorIndictmentRoutes(isTrafficViolation), + caseToOpen, + ) + } } } diff --git a/libs/judicial-system/consts/src/lib/consts.ts b/libs/judicial-system/consts/src/lib/consts.ts index ba40d85db437..8fb4af170a2d 100644 --- a/libs/judicial-system/consts/src/lib/consts.ts +++ b/libs/judicial-system/consts/src/lib/consts.ts @@ -86,65 +86,32 @@ export const InvestigationCaseTypes = [ // Date/time formats export const TIME_FORMAT = 'HH:mm' -// Routes -export const CASES_ROUTE = '/krofur' -export const USERS_ROUTE = '/notendur' -export const CREATE_USER_ROUTE = '/notendur/nyr' -export const CHANGE_USER_ROUTE = '/notendur/breyta' -export const SIGNED_VERDICT_OVERVIEW_ROUTE = '/krafa/yfirlit' -export const CLOSED_INDICTMENT_OVERVIEW_ROUTE = '/akaera/yfirlit' - -export const CREATE_RESTRICTION_CASE_ROUTE = '/krafa/ny/gaesluvardhald' -export const CREATE_TRAVEL_BAN_ROUTE = '/krafa/ny/farbann' -export const CREATE_INVESTIGATION_CASE_ROUTE = '/krafa/ny/rannsoknarheimild' -export const CREATE_INDICTMENT_ROUTE = '/akaera/ny' - +//#region Defence user routes +export const DEFENDER_CASES_ROUTE = '/verjandi/krofur' export const DEFENDER_ROUTE = '/verjandi/krafa' export const DEFENDER_INDICTMENT_ROUTE = '/verjandi/akaera' + export const DEFENDER_APPEAL_ROUTE = '/verjandi/kaera' export const DEFENDER_APPEAL_FILES_ROUTE = '/verjandi/kaera/gogn' export const DEFENDER_STATEMENT_ROUTE = '/verjandi/greinargerd' -export const DEFENDER_CASES_ROUTE = '/verjandi/krofur' - -export const APPEAL_ROUTE = '/kaera' -export const APPEAL_FILES_ROUTE = '/kaera/gogn' -export const STATEMENT_ROUTE = '/greinargerd' - -/* PROSECUTOR ROUTES START */ -export const RESTRICTION_CASE_DEFENDANT_ROUTE = '/krafa/sakborningur' -export const RESTRICTION_CASE_HEARING_ARRANGEMENTS_ROUTE = '/krafa/fyrirtaka' -export const RESTRICTION_CASE_POLICE_DEMANDS_ROUTE = - '/krafa/domkrofur-og-lagagrundvollur' -export const RESTRICTION_CASE_POLICE_REPORT_ROUTE = '/krafa/greinargerd' -export const RESTRICTION_CASE_CASE_FILES_ROUTE = '/krafa/rannsoknargogn' -export const RESTRICTION_CASE_OVERVIEW_ROUTE = '/krafa/stadfesta' - -export const INVESTIGATION_CASE_DEFENDANT_ROUTE = - '/krafa/rannsoknarheimild/varnaradili' -export const INVESTIGATION_CASE_HEARING_ARRANGEMENTS_ROUTE = - '/krafa/rannsoknarheimild/fyrirtaka' -export const INVESTIGATION_CASE_POLICE_DEMANDS_ROUTE = - '/krafa/rannsoknarheimild/domkrofur-og-lagagrundvollur' -export const INVESTIGATION_CASE_POLICE_REPORT_ROUTE = - '/krafa/rannsoknarheimild/greinargerd' -export const INVESTIGATION_CASE_CASE_FILES_ROUTE = - '/krafa/rannsoknarheimild/rannsoknargogn' -export const INVESTIGATION_CASE_POLICE_CONFIRMATION_ROUTE = - '/krafa/rannsoknarheimild/stadfesta' - -export const INDICTMENTS_DEFENDANT_ROUTE = '/akaera/akaerdi' -export const INDICTMENTS_POLICE_CASE_FILES_ROUTE = '/akaera/malsgogn' -export const INDICTMENTS_CASE_FILE_ROUTE = '/akaera/skjalaskra' -export const INDICTMENTS_PROCESSING_ROUTE = '/akaera/malsmedferd' -export const INDICTMENTS_TRAFFIC_VIOLATION_ROUTE = '/akaera/akaera' -export const INDICTMENTS_CASE_FILES_ROUTE = '/akaera/domskjol' -export const INDICTMENTS_OVERVIEW_ROUTE = '/akaera/stadfesta' +//#endregion Defence user routes +//#region Public prosecutor user routes export const PUBLIC_PROSECUTOR_STAFF_INDICTMENT_OVERVIEW_ROUTE = '/rikissaksoknari/akaera/yfirlit' -/* PROSECUTOR ROUTES END */ +//#endregion Public prosecutor user routes + +//#region Court of appeals user routes +export const COURT_OF_APPEAL_OVERVIEW_ROUTE = '/landsrettur/yfirlit' +export const COURT_OF_APPEAL_CASES_ROUTE = '/landsrettur/krofur' +export const COURT_OF_APPEAL_CASE_ROUTE = '/landsrettur/kaera' +export const COURT_OF_APPEAL_RULING_ROUTE = '/landsrettur/urskurdur' +export const COURT_OF_APPEAL_RESULT_ROUTE = '/landsrettur/nidurstada' +export const COURT_OF_APPEAL_SUMMARY_ROUTE = '/landsrettur/samantekt' +export const COURT_OF_APPEAL_CASE_WITHDRAWN_ROUTE = '/landsrettur/nidurfelling' +//#endregion Court of appeals user routes -/* DISTRICT COURT ROUTES START */ +//#region District court user routes export const RESTRICTION_CASE_RECEPTION_AND_ASSIGNMENT_ROUTE = '/domur/mottaka' export const RESTRICTION_CASE_COURT_OVERVIEW_ROUTE = '/domur/krafa' export const RESTRICTION_CASE_COURT_HEARING_ARRANGEMENTS_ROUTE = @@ -159,10 +126,10 @@ export const INVESTIGATION_CASE_OVERVIEW_ROUTE = '/domur/rannsoknarheimild/yfirlit' export const INVESTIGATION_CASE_COURT_HEARING_ARRANGEMENTS_ROUTE = '/domur/rannsoknarheimild/fyrirtaka' -export const INVESTIGATION_CASE_COURT_RECORD_ROUTE = - '/domur/rannsoknarheimild/thingbok' export const INVESTIGATION_CASE_RULING_ROUTE = '/domur/rannsoknarheimild/urskurdur' +export const INVESTIGATION_CASE_COURT_RECORD_ROUTE = + '/domur/rannsoknarheimild/thingbok' export const INVESTIGATION_CASE_CONFIRMATION_ROUTE = '/domur/rannsoknarheimild/stadfesta' @@ -174,18 +141,59 @@ export const INDICTMENTS_DEFENDER_ROUTE = '/domur/akaera/malflytjendur' export const INDICTMENTS_CONCLUSION_ROUTE = '/domur/akaera/nidurstada' export const INDICTMENTS_SUMMARY_ROUTE = '/domur/akaera/samantekt' export const INDICTMENTS_COMPLETED_ROUTE = '/domur/akaera/lokid' -/* DISTRICT COURT ROUTES END */ +//#endregion District court user routes -/* COURT OF APPEALS ROUTES START */ -export const COURT_OF_APPEAL_OVERVIEW_ROUTE = '/landsrettur/yfirlit' -export const COURT_OF_APPEAL_CASES_ROUTE = '/landsrettur/krofur' -export const COURT_OF_APPEAL_CASE_ROUTE = '/landsrettur/kaera' -export const COURT_OF_APPEAL_RULING_ROUTE = '/landsrettur/urskurdur' -export const COURT_OF_APPEAL_RESULT_ROUTE = '/landsrettur/nidurstada' -export const COURT_OF_APPEAL_SUMMARY_ROUTE = '/landsrettur/samantekt' -export const COURT_OF_APPEAL_CASE_WITHDRAWN_ROUTE = '/landsrettur/nidurfelling' +//#region Prosecutor user routes +export const CREATE_RESTRICTION_CASE_ROUTE = '/krafa/ny/gaesluvardhald' +export const CREATE_TRAVEL_BAN_ROUTE = '/krafa/ny/farbann' +export const CREATE_INVESTIGATION_CASE_ROUTE = '/krafa/ny/rannsoknarheimild' +export const CREATE_INDICTMENT_ROUTE = '/akaera/ny' + +export const RESTRICTION_CASE_DEFENDANT_ROUTE = '/krafa/sakborningur' +export const RESTRICTION_CASE_HEARING_ARRANGEMENTS_ROUTE = '/krafa/fyrirtaka' +export const RESTRICTION_CASE_POLICE_DEMANDS_ROUTE = + '/krafa/domkrofur-og-lagagrundvollur' +export const RESTRICTION_CASE_POLICE_REPORT_ROUTE = '/krafa/greinargerd' +export const RESTRICTION_CASE_CASE_FILES_ROUTE = '/krafa/rannsoknargogn' +export const RESTRICTION_CASE_OVERVIEW_ROUTE = '/krafa/stadfesta' + +export const INVESTIGATION_CASE_DEFENDANT_ROUTE = + '/krafa/rannsoknarheimild/varnaradili' +export const INVESTIGATION_CASE_HEARING_ARRANGEMENTS_ROUTE = + '/krafa/rannsoknarheimild/fyrirtaka' +export const INVESTIGATION_CASE_POLICE_DEMANDS_ROUTE = + '/krafa/rannsoknarheimild/domkrofur-og-lagagrundvollur' +export const INVESTIGATION_CASE_POLICE_REPORT_ROUTE = + '/krafa/rannsoknarheimild/greinargerd' +export const INVESTIGATION_CASE_CASE_FILES_ROUTE = + '/krafa/rannsoknarheimild/rannsoknargogn' +export const INVESTIGATION_CASE_POLICE_CONFIRMATION_ROUTE = + '/krafa/rannsoknarheimild/stadfesta' + +export const APPEAL_ROUTE = '/kaera' +export const APPEAL_FILES_ROUTE = '/kaera/gogn' +export const STATEMENT_ROUTE = '/greinargerd' + +export const INDICTMENTS_DEFENDANT_ROUTE = '/akaera/akaerdi' +export const INDICTMENTS_POLICE_CASE_FILES_ROUTE = '/akaera/malsgogn' +export const INDICTMENTS_CASE_FILE_ROUTE = '/akaera/skjalaskra' +export const INDICTMENTS_PROCESSING_ROUTE = '/akaera/malsmedferd' +export const INDICTMENTS_TRAFFIC_VIOLATION_ROUTE = '/akaera/akaera' +export const INDICTMENTS_CASE_FILES_ROUTE = '/akaera/domskjol' +export const INDICTMENTS_OVERVIEW_ROUTE = '/akaera/stadfesta' +export const CLOSED_INDICTMENT_OVERVIEW_ROUTE = '/akaera/yfirlit' +//#endregion Prosecutor user routes + +//#region Admin user routes +export const USERS_ROUTE = '/notendur' +export const CREATE_USER_ROUTE = '/notendur/nyr' +export const CHANGE_USER_ROUTE = '/notendur/breyta' +//#endregion Admin user routes -/* COURT OF APPEALS ROUTES END */ +//#region Shared routes +export const CASES_ROUTE = '/krofur' +export const SIGNED_VERDICT_OVERVIEW_ROUTE = '/krafa/yfirlit' +//#endregion Shared routes export const prosecutorRestrictionCasesRoutes = [ RESTRICTION_CASE_DEFENDANT_ROUTE, @@ -233,14 +241,6 @@ export const courtInvestigationCasesRoutes = [ INVESTIGATION_CASE_CONFIRMATION_ROUTE, ] -export const courtIndictmentRoutes = [ - INDICTMENTS_COURT_OVERVIEW_ROUTE, - INDICTMENTS_RECEPTION_AND_ASSIGNMENT_ROUTE, - INDICTMENTS_SUBPOENA_ROUTE, - INDICTMENTS_DEFENDER_ROUTE, - INDICTMENTS_CONCLUSION_ROUTE, -] - // Feedback export const FEEDBACK_FORM_URL = 'https://form.asana.com?k=45fPB_e65kYFDjvG-18f0w&d=203394141643832' From af29933983a9f4f5c73c76b4eacece73969cd5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnlaugur=20Gu=C3=B0mundsson?= <34029342+GunnlaugurG@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:17:08 +0000 Subject: [PATCH 47/82] feat(service-desk): WebApiCrypto encryption (#14768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create encrypt and decrypt actions to cypher text using the Web Api Crypto library * merged with main * fix test * fix code so test will run on node rather then jsdom * fix build after nullable unmask/mask * fix pr comments * chore: nx format:write update dirty files * fix encryption to be url friendly * chore: nx format:write update dirty files --------- Co-authored-by: Sævar Már Atlason Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../national-registry/src/lib/v3/mapper.ts | 16 ++- .../src/screens/User/User.loader.ts | 2 +- .../src/screens/Users/Users.action.ts | 9 +- .../service-desk/src/screens/Users/Users.tsx | 6 +- .../src/screens/BioChild/BioChild.tsx | 21 +++- .../src/screens/ChildCustody/ChildCustody.tsx | 27 +++- .../UserInfoOverview/UserInfoOverview.tsx | 78 ++++++++---- .../utils/src/lib/simpleEncryption.spec.ts | 31 +++-- libs/shared/utils/src/lib/simpleEncryption.ts | 115 +++++++++++++----- 9 files changed, 216 insertions(+), 89 deletions(-) diff --git a/libs/api/domains/national-registry/src/lib/v3/mapper.ts b/libs/api/domains/national-registry/src/lib/v3/mapper.ts index 8a15b6a009e0..f11fc3922bd3 100644 --- a/libs/api/domains/national-registry/src/lib/v3/mapper.ts +++ b/libs/api/domains/national-registry/src/lib/v3/mapper.ts @@ -31,12 +31,12 @@ import * as kennitala from 'kennitala' import { maskString, isDefined } from '@island.is/shared/utils' import { FamilyChild, User } from './types' -export const formatPersonDiscriminated = ( +export const formatPersonDiscriminated = async ( individual?: EinstaklingurDTOAllt | null, nationalId?: string, useFakeData?: boolean, -): PersonV3 | null => { - const person = formatPerson(individual, nationalId) +): Promise => { + const person = await formatPerson(individual, nationalId) if (!person) { return null } @@ -64,14 +64,18 @@ export const formatChildCustody = ( } } -export const formatPerson = ( +export const formatPerson = async ( individual?: EinstaklingurDTOAllt | null, nationalId?: string, -): Person | null => { +): Promise => { if (individual === null || !individual?.kennitala || !individual?.nafn) { return null } + const maskedNationalId = nationalId + ? await maskString(individual.kennitala, nationalId) + : null + return { nationalId: individual.kennitala, fullName: individual.nafn, @@ -84,7 +88,7 @@ export const formatPerson = ( ), ...(nationalId && individual.kennitala && { - baseId: maskString(individual.kennitala, nationalId), + baseId: maskedNationalId, }), //DEPRECATION LINE -- below shall be removed diff --git a/libs/portals/admin/service-desk/src/screens/User/User.loader.ts b/libs/portals/admin/service-desk/src/screens/User/User.loader.ts index d3de811a97ac..f98ebaab0995 100644 --- a/libs/portals/admin/service-desk/src/screens/User/User.loader.ts +++ b/libs/portals/admin/service-desk/src/screens/User/User.loader.ts @@ -21,7 +21,7 @@ export const userLoader: WrappedLoaderFn = ({ client, userInfo }) => { if (!nationalId) throw new Error('User not found') const unMaskedNationalId = - unmaskString(nationalId, userInfo.profile.nationalId) ?? '' + (await unmaskString(nationalId, userInfo.profile.nationalId)) ?? '' const res = await client.query< GetUserProfileByNationalIdQuery, diff --git a/libs/portals/admin/service-desk/src/screens/Users/Users.action.ts b/libs/portals/admin/service-desk/src/screens/Users/Users.action.ts index c14a1d88b447..4d723cad3321 100644 --- a/libs/portals/admin/service-desk/src/screens/Users/Users.action.ts +++ b/libs/portals/admin/service-desk/src/screens/Users/Users.action.ts @@ -1,8 +1,5 @@ import { z } from 'zod' import { redirect } from 'react-router-dom' -import { isEmail } from 'class-validator' -import * as kennitala from 'kennitala' -import { parsePhoneNumber } from 'libphonenumber-js' import { RawRouterActionResponse, @@ -13,7 +10,7 @@ import { validateFormData, ValidateFormDataResult, } from '@island.is/react-spa/shared' -import { isSearchTermValid, maskString } from '@island.is/shared/utils' +import { maskString, isSearchTermValid } from '@island.is/shared/utils' import { GetPaginatedUserProfilesDocument, @@ -88,10 +85,10 @@ export const UsersAction: WrappedActionFn = replaceParams({ href: ServiceDeskPaths.User, params: { - nationalId: maskString( + nationalId: (await maskString( respData[0].nationalId, userInfo.profile.nationalId, - ) as string, + )) as string, }, }), ) diff --git a/libs/portals/admin/service-desk/src/screens/Users/Users.tsx b/libs/portals/admin/service-desk/src/screens/Users/Users.tsx index 524e73c8cb02..6e66784fba2a 100644 --- a/libs/portals/admin/service-desk/src/screens/Users/Users.tsx +++ b/libs/portals/admin/service-desk/src/screens/Users/Users.tsx @@ -97,16 +97,16 @@ const Users = () => { variant="text" icon="arrowForward" size="small" - onClick={() => + onClick={async () => navigate( replaceParams({ href: ServiceDeskPaths.User, params: { nationalId: - maskString( + (await maskString( nationalId, userInfo?.profile?.nationalId ?? '', - ) ?? '', + )) ?? '', }, }), ) diff --git a/libs/service-portal/information/src/screens/BioChild/BioChild.tsx b/libs/service-portal/information/src/screens/BioChild/BioChild.tsx index fa514175e3b5..0b5153e8870c 100644 --- a/libs/service-portal/information/src/screens/BioChild/BioChild.tsx +++ b/libs/service-portal/information/src/screens/BioChild/BioChild.tsx @@ -23,6 +23,7 @@ import { spmm } from '../../lib/messages' import { unmaskString } from '@island.is/shared/utils' import { Problem } from '@island.is/react-spa/shared' import { useNationalRegistryBioChildQuery } from './BioChild.generated' +import { useEffect, useState } from 'react' type UseParams = { baseId: string @@ -33,11 +34,29 @@ const BioChild = () => { const { formatMessage } = useLocale() const userInfo = useUserInfo() const { baseId } = useParams() as UseParams + const [unmaskedBaseId, setUnmaskedBaseId] = useState(null) + + useEffect(() => { + const decrypt = async () => { + try { + const decrypted = await unmaskString( + baseId, + userInfo.profile.nationalId, + ) + setUnmaskedBaseId(decrypted ?? null) + } catch (e) { + console.error('Failed to decrypt baseId', e) + } + } + + decrypt() + }, [baseId, userInfo]) const { data, loading, error } = useNationalRegistryBioChildQuery({ variables: { - childNationalId: unmaskString(baseId, userInfo.profile.nationalId), + childNationalId: unmaskedBaseId, }, + skip: !unmaskedBaseId, }) const child = data?.nationalRegistryPerson?.biologicalChildren?.[0].details diff --git a/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx b/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx index 7d9e9d3f874f..6c85cb59e7f1 100644 --- a/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx +++ b/libs/service-portal/information/src/screens/ChildCustody/ChildCustody.tsx @@ -1,4 +1,5 @@ import { useUserInfo } from '@island.is/auth/react' +import { defineMessage } from 'react-intl' import { Box, Button, @@ -11,21 +12,21 @@ import { import { useLocale, useNamespaces } from '@island.is/localization' import { Problem } from '@island.is/react-spa/shared' import { + formatNationalId, IntroHeader, LinkButton, + m, THJODSKRA_SLUG, UserInfoLine, - formatNationalId, - m, } from '@island.is/service-portal/core' import { unmaskString } from '@island.is/shared/utils' -import { defineMessage } from 'react-intl' import { useParams } from 'react-router-dom' import { TwoColumnUserInfoLine } from '../../components/TwoColumnUserInfoLine/TwoColumnUserInfoLine' import { formatNameBreaks } from '../../helpers/formatting' import { natRegGenderMessageDescriptorRecord } from '../../helpers/localizationHelpers' import { spmm, urls } from '../../lib/messages' import { useNationalRegistryChildCustodyQuery } from './ChildCustody.generated' +import { useEffect, useState } from 'react' type UseParams = { baseId: string @@ -36,11 +37,29 @@ const ChildCustody = () => { const { formatMessage } = useLocale() const userInfo = useUserInfo() const { baseId } = useParams() as UseParams + const [unmaskedBaseId, setUnmaskedBaseId] = useState(null) + + useEffect(() => { + const decrypt = async () => { + try { + const decrypted = await unmaskString( + baseId, + userInfo.profile.nationalId, + ) + setUnmaskedBaseId(decrypted) + } catch (error) { + console.error('Error encrypting text:', error) + } + } + + decrypt() + }, [baseId, userInfo]) const { data, loading, error } = useNationalRegistryChildCustodyQuery({ variables: { - childNationalId: unmaskString(baseId, userInfo.profile.nationalId), + childNationalId: unmaskedBaseId, }, + skip: !unmaskedBaseId, }) const child = data?.nationalRegistryPerson?.childCustody?.[0]?.details diff --git a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx index 124cd36d94ad..7d3878a15bf9 100644 --- a/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx +++ b/libs/service-portal/information/src/screens/UserInfoOverview/UserInfoOverview.tsx @@ -14,11 +14,14 @@ import { spmm } from '../../lib/messages' import { maskString } from '@island.is/shared/utils' import { useUserInfoOverviewQuery } from './UserInfoOverview.generated' import { Problem } from '@island.is/react-spa/shared' +import { useEffect, useState } from 'react' const UserInfoOverview = () => { useNamespaces('sp.family') const { formatMessage } = useLocale() const userInfo = useUserInfo() + const [childCards, setChildCards] = useState([]) + const [bioChildrenCards, setBioChildrenCards] = useState([]) const { data, error, loading } = useUserInfoOverviewQuery() @@ -30,6 +33,57 @@ const UserInfoOverview = () => { (child) => !childCustody?.some((c) => c.nationalId === child.nationalId), ) + useEffect(() => { + const fetchChildCustodyData = async () => { + try { + if (childCustody) { + const childrenData = await Promise.all( + childCustody.map(async (child) => { + const baseId = await maskString( + child.nationalId, + userInfo.profile.nationalId, + ) + return ( + + ) + }), + ) + setChildCards(childrenData) + } + if (bioChildren) { + const bioChildrenData = await Promise.all( + bioChildren.map(async (child) => { + const baseId = await maskString( + child.nationalId, + userInfo.profile.nationalId, + ) + return ( + + ) + }), + ) + setBioChildrenCards(bioChildrenData) + } + } catch (e) { + console.error('Failed setting childCards', e) + } + } + + fetchChildCustodyData() + }, [data, userInfo.profile.nationalId]) + return ( <> { familyRelation="spouse" /> )} - {childCustody?.map((child) => ( - - ))} - {bioChildren?.map((child) => ( - - ))} + {childCards} + {bioChildrenCards} )} diff --git a/libs/shared/utils/src/lib/simpleEncryption.spec.ts b/libs/shared/utils/src/lib/simpleEncryption.spec.ts index 3cb53550d976..1d25b93164dd 100644 --- a/libs/shared/utils/src/lib/simpleEncryption.spec.ts +++ b/libs/shared/utils/src/lib/simpleEncryption.spec.ts @@ -1,29 +1,34 @@ +/** + * @jest-environment node + */ + import { maskString, unmaskString } from './simpleEncryption' const originalText = 'Original Jest Text!' const secretKey = 'not-really-secret-key' describe('Encryption and Decryption Functions', () => { - test('Encrypt and decrypt a string successfully', () => { - const encrypted = maskString(originalText, secretKey) + test('Encrypt and decrypt a string successfully', async () => { + const encrypted = await maskString(originalText, secretKey) // Check for successful encryption expect(encrypted).not.toBe(originalText) + expect(encrypted).not.toBeNull() + + // If null check succeeds, we can safely cast to string for the unmasking test + const textToDecrypt = encrypted as string - // Check for successful decryption - if (encrypted !== null) { - const decrypted = unmaskString(encrypted, secretKey) - expect(decrypted).toBe(originalText) - expect(encrypted).not.toBe(originalText) - } else { - // Fail the test explicitly if encryption failed - fail('Encryption failed') - } + const decrypted = await unmaskString(textToDecrypt, secretKey) + expect(decrypted).toBe(originalText) + expect(encrypted).not.toBe(originalText) }) - test('Return null in case of decryption failure', () => { + test('Return null in case of decryption failure', async () => { // Example: testing decryption failure - const decryptedFailure = unmaskString('invalid-encrypted-text', secretKey) + const decryptedFailure = await unmaskString( + 'invalid-encrypted-text', + secretKey, + ) expect(decryptedFailure).toBeNull() }) }) diff --git a/libs/shared/utils/src/lib/simpleEncryption.ts b/libs/shared/utils/src/lib/simpleEncryption.ts index 472c7c00d9b6..9d2d4cf0f010 100644 --- a/libs/shared/utils/src/lib/simpleEncryption.ts +++ b/libs/shared/utils/src/lib/simpleEncryption.ts @@ -1,59 +1,108 @@ -import { Base64 } from 'js-base64' -import { createCipheriv, createDecipheriv, createHash } from 'crypto' +const ALGORITHM = 'AES-CBC' +const DELIMITER = ':' // Delimiter to separate IV and encrypted text -const ALGORITHM = 'aes-256-cbc' +const crypto = global.window ? window.crypto : require('crypto') + +// Function to convert ArrayBuffer to base64 +const bufferToBase64 = (buffer: ArrayBuffer): string => { + return btoa(String.fromCharCode(...new Uint8Array(buffer))) +} + +// Function to convert base64 to ArrayBuffer +const base64ToBuffer = (base64: string): ArrayBuffer => { + return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)).buffer +} + +const str2ab = (str: string): ArrayBuffer => { + const encoder = new TextEncoder() + return encoder.encode(str) +} + +// Function to derive a cryptographic key from a text password +const deriveKey = async (password: string): Promise => { + const keyMaterial = await crypto.subtle.importKey( + 'raw', + str2ab(password), + { name: 'PBKDF2' }, + false, + ['deriveKey'], + ) + return crypto.subtle.deriveKey( + { + name: 'PBKDF2', + // we do not need to hide this in environment variables since we are not using it for secure encryption but rather to mask strings, so they don't show up in logs + salt: new TextEncoder().encode('unique-salt-value=='), + iterations: 1000, + hash: 'SHA-256', + }, + keyMaterial, + { name: ALGORITHM, length: 256 }, + true, + ['encrypt', 'decrypt'], + ) +} /** * * @param text The string you wish to hide * @param key You secret key - * @returns URL safe Base64 */ -export const maskString = (text: string, key: string): string | null => { +export const maskString = async ( + text: string, + key: string, +): Promise => { try { - const derivedKey = hashKey(key) + const derivedKey = await deriveKey(key) + const iv = crypto.getRandomValues(new Uint8Array(16)) // AES-CBC recommended IV length is 16 bytes - const cipher = createCipheriv(ALGORITHM, derivedKey, Buffer.alloc(16)) - const encrypted = - cipher.update(text, 'utf-8', 'base64') + cipher.final('base64') + const encrypted = await crypto.subtle.encrypt( + { + name: ALGORITHM, + iv: iv, + }, + derivedKey, + str2ab(text), + ) + const ivStr = bufferToBase64(iv) + const encryptedStr = bufferToBase64(encrypted) - return Base64.encodeURI(encrypted) + return encodeURIComponent(ivStr + DELIMITER + encryptedStr) } catch (e) { - console.error({ - name: 'unmaskString', - error: e, - }) + console.error(e) return null } } /** - * @param encryptedText Base64 returned from encrypt() - * @param key The secret key you used in encrypt() - * @returns Reveals the string hidden by encrypt() + * @param encryptedText Base64 returned from maskString() + * @param key The secret key you used in maskString() + * @returns Reveals the string hidden by maskString() */ -export const unmaskString = ( +export const unmaskString = async ( encryptedText: string, key: string, -): string | null => { +): Promise => { try { - const encryptedData = Base64.decode(encryptedText) - const derivedKey = hashKey(key) - const decipher = createDecipheriv(ALGORITHM, derivedKey, Buffer.alloc(16)) + encryptedText = decodeURIComponent(encryptedText) + const [ivPart, encryptedPart] = encryptedText.split(DELIMITER) + const iv = base64ToBuffer(ivPart) + + const encrypted = base64ToBuffer(encryptedPart) - return ( - decipher.update(encryptedData, 'base64', 'utf-8') + - decipher.final('utf-8') + const derivedKey = await deriveKey(key) + const decrypted = await crypto.subtle.decrypt( + { + name: ALGORITHM, + iv: iv, + }, + derivedKey, + encrypted, ) + + const decoder = new TextDecoder() + return decoder.decode(decrypted) } catch (e) { - console.error({ - name: 'unmaskString', - error: e, - }) + console.error(e) return null } } - -function hashKey(key: string): Buffer { - return createHash('sha256').update(key).digest() -} From 760c6bb74165083d200ffa156228516e15a744ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Mon, 3 Jun 2024 13:46:37 +0000 Subject: [PATCH 48/82] chore(service-portal): No scope notifications (#15053) * no scope notifications * remove unused * Add alt texg * Minor refactor --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../DocumentsEmpty/DocumentsEmpty.css.ts | 13 ++++ .../DocumentsEmpty/DocumentsEmpty.tsx | 59 +++++++++++++++++++ .../src/components/Header/Header.tsx | 9 ++- .../src/components/Layout/FullWidthLayout.tsx | 21 ++++--- .../Notifications/NotificationButton.tsx | 16 ++++- .../Notifications/Notifications.css.ts | 11 ++++ .../src/screens/Dashboard/Dashboard.tsx | 25 +------- 7 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.css.ts create mode 100644 apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.tsx diff --git a/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.css.ts b/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.css.ts new file mode 100644 index 000000000000..3ae765b21300 --- /dev/null +++ b/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.css.ts @@ -0,0 +1,13 @@ +import { theme } from '@island.is/island-ui/theme' +import { style } from '@vanilla-extract/css' + +export const lock = style({ + position: 'absolute', + zIndex: 1, + top: theme.spacing[2], + right: theme.spacing[3], +}) + +export const img = style({ + height: 180, +}) diff --git a/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.tsx b/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.tsx new file mode 100644 index 000000000000..516d77d1db4b --- /dev/null +++ b/apps/service-portal/src/components/DocumentsEmpty/DocumentsEmpty.tsx @@ -0,0 +1,59 @@ +import { Box, Icon, Text } from '@island.is/island-ui/core' +import { useLocale } from '@island.is/localization' +import { m } from '@island.is/service-portal/core' +import * as styles from './DocumentsEmpty.css' + +interface Props { + hasDelegationAccess: boolean +} + +export const DocumentsEmpty = ({ hasDelegationAccess }: Props) => { + const { formatMessage } = useLocale() + + return ( + + + {hasDelegationAccess + ? formatMessage(m.emptyDocumentsList) + : formatMessage(m.accessNeeded)} + + {!hasDelegationAccess && ( + + {formatMessage(m.accessDeniedText)} + + )} + + { + No access + } + + {!hasDelegationAccess && ( + + )} + + ) +} + +export default DocumentsEmpty diff --git a/apps/service-portal/src/components/Header/Header.tsx b/apps/service-portal/src/components/Header/Header.tsx index 5bd6d74d1eab..21c913b99da0 100644 --- a/apps/service-portal/src/components/Header/Header.tsx +++ b/apps/service-portal/src/components/Header/Header.tsx @@ -26,6 +26,7 @@ import { useWindowSize } from 'react-use' import NotificationButton from '../Notifications/NotificationButton' import Sidemenu from '../Sidemenu/Sidemenu' import * as styles from './Header.css' +import { DocumentsScope } from '@island.is/auth/scopes' export type MenuTypes = 'side' | 'user' | 'notifications' | undefined interface Props { @@ -57,6 +58,10 @@ export const Header = ({ position }: Props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + const hasNotificationsDelegationAccess = user?.scopes?.includes( + DocumentsScope.main, + ) + return (
@@ -96,7 +101,6 @@ export const Header = ({ position }: Props) => { flexWrap="nowrap" marginLeft={[1, 1, 2]} > - {user && } { setMenuOpen(val)} showMenu={menuOpen === 'notifications'} + disabled={!hasNotificationsDelegationAccess} /> )} + {user && } + - - )} - + + + ) } diff --git a/libs/service-portal/licenses/src/screens/LicenseDetail/LicenseDetail.tsx b/libs/service-portal/licenses/src/screens/LicenseDetail/LicenseDetail.tsx index 6ea1a4d337d4..5d8f5a4ef1f6 100644 --- a/libs/service-portal/licenses/src/screens/LicenseDetail/LicenseDetail.tsx +++ b/libs/service-portal/licenses/src/screens/LicenseDetail/LicenseDetail.tsx @@ -342,7 +342,6 @@ const LicenseDetail = () => { useNamespaces('sp.license') const { formatMessage } = useLocale() const { data: userProfile } = useUserProfile() - const { pathname } = useLocation() const locale = userProfile?.locale ?? 'is' const { type, id } = useParams() as UseParams const licenseType = type ? getTypeFromPath(type) : undefined From fdc850748478e5ccf73bd5be5f4a076f1a41f692 Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:07:33 +0000 Subject: [PATCH 54/82] fix(inheritance-report): dataschema deceased was married (#15063) * fix(inheritance-report): dataschema deceased was married * test --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../inheritance-report/src/fields/AssetsRepeater/index.tsx | 3 +-- .../templates/inheritance-report/src/forms/sections/heirs.ts | 4 ---- .../templates/inheritance-report/src/lib/dataSchema.ts | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx index 646c4baf63ab..a782f59d59ff 100644 --- a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx @@ -99,8 +99,7 @@ export const AssetsRepeater: FC< useEffect(() => { calculateTotal() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [fields]) const handleAddRepeaterFields = () => { const values = props.fields.map((field: object) => { diff --git a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts index 3fac8faf7869..8cb2dd63ced0 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/heirs.ts @@ -60,10 +60,6 @@ export const heirs = buildSection({ id: 'netPropertyForExchange', title: '', }), - buildDescriptionField({ - id: 'customShare.customSpouseSharePercentage', - title: '', - }), buildCustomField({ title: '', id: 'share', diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index 649d954c57c9..dcce0189574f 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -593,7 +593,7 @@ export const inheritanceReportSchema = z.object({ netPropertyForExchange: z.number(), customShare: z .object({ - deceasedWasMarried: z.string().min(1), + deceasedWasMarried: z.enum([YES, NO]), deceasedHadAssets: z.string().optional(), hasCustomSpouseSharePercentage: z.string().optional(), customSpouseSharePercentage: z.string().optional(), From 7a9ceaeb5f34c6e311b64158786ca08f181d7627 Mon Sep 17 00:00:00 2001 From: lommi Date: Mon, 3 Jun 2024 17:06:08 +0000 Subject: [PATCH 55/82] ci: fix affected all (#15066) --- .github/workflows/pullrequest.yml | 3 --- .github/workflows/push.yml | 5 ----- scripts/ci/00_prepare-base-tags.sh | 1 + 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 499977254e35..9c5dcaa47d2c 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -117,9 +117,6 @@ jobs: source ./scripts/ci/00_prepare-base-tags.sh $(git merge-base HEAD $GITHUB_BASE_REF) git checkout $GITHUB_SHA echo "BASE=$BASE" >> $GITHUB_ENV - if [ -n "${NX_AFFECTED_ALL+x}" ]; then - echo "NX_AFFECTED_ALL=$NX_AFFECTED_ALL" >> $GITHUB_ENV - fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} HTML_URL: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index fbfc16389a00..ed33617bba7a 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -345,11 +345,6 @@ jobs: git checkout $GITHUB_SHA echo "BASE=$BASE" >> $GITHUB_ENV echo "LAST_GOOD_BUILD_DOCKER_TAG=${LAST_GOOD_BUILD_DOCKER_TAG}" >> $GITHUB_OUTPUT - - if [ -n "${NX_AFFECTED_ALL+x}" ]; then - echo "NX_AFFECTED_ALL=$NX_AFFECTED_ALL" >> $GITHUB_ENV - fi - - name: Docker login to ECR repo run: ./scripts/ci/docker-login-ecr.sh env: diff --git a/scripts/ci/00_prepare-base-tags.sh b/scripts/ci/00_prepare-base-tags.sh index c26708a24fc3..4231289a1658 100755 --- a/scripts/ci/00_prepare-base-tags.sh +++ b/scripts/ci/00_prepare-base-tags.sh @@ -10,6 +10,7 @@ cp -r "$ROOT/.github/actions/dist/." "$tempRepo" LAST_GOOD_BUILD=$(DEBUG="*,-simple-git" REPO_ROOT="$ROOT" node $tempRepo/main.js) if echo "$LAST_GOOD_BUILD" | grep -q 'full_rebuild_needed'; then export NX_AFFECTED_ALL=true + echo "NX_AFFECTED_ALL=$NX_AFFECTED_ALL" >> $GITHUB_ENV exit 0 fi echo "Stickman done" From 623be7309964baefffd086b0a6c58b143c9a4e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Mon, 3 Jun 2024 21:35:39 +0000 Subject: [PATCH 56/82] fix(j-s): MD5 Indictment File Hash (#15052) * Fixes storage of md5 indictment file hash * Adds missing field --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/app/modules/case/limitedAccessCase.service.ts | 1 + .../backend/src/app/modules/file/file.service.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index 3cef3a2f246c..10ddc4008743 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -97,6 +97,7 @@ export const attributes: (keyof Case)[] = [ 'appealRulingModifiedHistory', 'requestAppealRulingNotToBePublished', 'prosecutorsOfficeId', + 'indictmentHash', ] export interface LimitedAccessUpdateCase diff --git a/apps/judicial-system/backend/src/app/modules/file/file.service.ts b/apps/judicial-system/backend/src/app/modules/file/file.service.ts index 870565dcef16..42f0f22f76f3 100644 --- a/apps/judicial-system/backend/src/app/modules/file/file.service.ts +++ b/apps/judicial-system/backend/src/app/modules/file/file.service.ts @@ -151,6 +151,7 @@ export class FileService { private async confirmIndictmentCaseFile( theCase: Case, + file: CaseFile, pdf: Buffer, ): Promise { const confirmationEvent = theCase.eventLogs?.find( @@ -178,7 +179,7 @@ export class FileService { const hash = CryptoJS.MD5(binaryPdf).toString(CryptoJS.enc.Hex) // No need to wait for the update to finish - this.fileModel.update({ hash }, { where: { id: theCase.id } }) + this.fileModel.update({ hash }, { where: { id: file.id } }) return binaryPdf }) @@ -203,7 +204,8 @@ export class FileService { theCase.state, file.key, !file.hash, - (content: Buffer) => this.confirmIndictmentCaseFile(theCase, content), + (content: Buffer) => + this.confirmIndictmentCaseFile(theCase, file, content), ) } @@ -350,7 +352,8 @@ export class FileService { theCase.state, file.key, !file.hash, - (content: Buffer) => this.confirmIndictmentCaseFile(theCase, content), + (content: Buffer) => + this.confirmIndictmentCaseFile(theCase, file, content), timeToLive, ) } From 1f60816fef5780f2dbb7c1a195cd48988cf6c218 Mon Sep 17 00:00:00 2001 From: berglindoma13 Date: Tue, 4 Jun 2024 08:37:00 +0000 Subject: [PATCH 57/82] feat(university-application): file uploads added to service (#15056) * adding function to blob * file upload test1 * small updates to application * optimization * optimization * refactoring * Update shared.service.ts refactoring --- .../application/dto/createApplicationDto.ts | 11 +- .../universityApplication.service.ts | 6 + .../src/lib/modules/shared/shared.service.ts | 24 +++- .../university/university.service.ts | 60 ++++++++-- .../src/components/SummaryBlock.tsx | 4 +- .../EducationDetails/DetailsRepeaterItem.tsx | 2 +- .../src/fields/Review/ProgramReview.tsx | 2 +- .../UniversityForm/FormerEducation/index.ts | 2 +- .../src/clientConfig.yaml | 103 +++++++++++++++--- .../lib/universityOfIcelandClient.service.ts | 16 ++- .../src/lib/model/application.ts | 7 ++ 11 files changed, 202 insertions(+), 35 deletions(-) diff --git a/apps/services/university-gateway/src/app/modules/application/dto/createApplicationDto.ts b/apps/services/university-gateway/src/app/modules/application/dto/createApplicationDto.ts index 9a9c7e42fbd6..72172ce99b76 100644 --- a/apps/services/university-gateway/src/app/modules/application/dto/createApplicationDto.ts +++ b/apps/services/university-gateway/src/app/modules/application/dto/createApplicationDto.ts @@ -106,10 +106,17 @@ class CreateApplicationFileDto { @IsString() @ApiProperty({ - description: 'Base 64 for file', + description: 'File type', + example: 'profskirteini', + }) + fileType!: string + + @IsString() + @ApiProperty({ + description: 'Blob for file', example: '', }) - base64!: string + blob!: Blob } class CreateApplicationEducationDto { diff --git a/apps/services/university-gateway/src/app/modules/application/universityApplication.service.ts b/apps/services/university-gateway/src/app/modules/application/universityApplication.service.ts index e21d52753ccc..127e9123f7e9 100644 --- a/apps/services/university-gateway/src/app/modules/application/universityApplication.service.ts +++ b/apps/services/university-gateway/src/app/modules/application/universityApplication.service.ts @@ -89,6 +89,11 @@ export class UniversityApplicationService { ) } + const allAttachments = applicationDto.educationList + .map((x) => x.degreeAttachments) + .filter((y) => !!y) + .flat() + // Wrap answers in obj that can be sent to libs/clients for universities const applicationObj: IApplication = { id: applicationDto.applicationId, @@ -116,6 +121,7 @@ export class UniversityApplicationService { educationOption: applicationDto.educationOption, workExperienceList: applicationDto.workExperienceList, extraFieldList: applicationDto.extraFieldList, + attachments: allAttachments, } // Create application in our DB diff --git a/libs/application/template-api-modules/src/lib/modules/shared/shared.service.ts b/libs/application/template-api-modules/src/lib/modules/shared/shared.service.ts index 2573811469ec..387a553e3757 100644 --- a/libs/application/template-api-modules/src/lib/modules/shared/shared.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/shared/shared.service.ts @@ -242,18 +242,16 @@ export class SharedTemplateApiService { ) } - async getAttachmentContentAsBase64( + async getS3File( application: ApplicationWithAttachments, attachmentKey: string, - ): Promise { + ) { const fileName = ( application.attachments as { [key: string]: string } )[attachmentKey] - const { bucket, key } = AmazonS3URI(fileName) - const uploadBucket = bucket const file = await this.s3 .getObject({ @@ -261,7 +259,23 @@ export class SharedTemplateApiService { Key: key, }) .promise() - const fileContent = file.Body as Buffer + return file.Body as Buffer + } + + async getAttachmentContentAsBase64( + application: ApplicationWithAttachments, + attachmentKey: string, + ): Promise { + const fileContent = await this.getS3File(application, attachmentKey) return fileContent?.toString('base64') || '' } + + async getAttachmentContentAsBlob( + application: ApplicationWithAttachments, + attachmentKey: string, + ): Promise { + const fileContent = await this.getS3File(application, attachmentKey) + const blob: Blob = new Blob([fileContent], { type: 'multipart/form-data' }) + return blob + } } diff --git a/libs/application/template-api-modules/src/lib/modules/templates/university/university.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/university/university.service.ts index 0af82ccaa355..2677fa205091 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/university/university.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/university/university.service.ts @@ -138,7 +138,16 @@ export class UniversityService extends BaseTemplateApiService { ? { degreeAttachments: await this.getFilesFromAttachment( application, - answers.educationDetails.exemptionDetails?.degreeAttachments, + answers.educationDetails.exemptionDetails?.degreeAttachments?.map( + (x, i) => { + const type = this.mapFileTypes(i) + return { + name: x.name, + key: x.key, + type: type, + } + }, + ), ), moreDetails: answers.educationDetails.exemptionDetails?.moreDetails, } @@ -160,7 +169,16 @@ export class UniversityService extends BaseTemplateApiService { answers.educationDetails.thirdLevelDetails?.moreDetails, degreeAttachments: await this.getFilesFromAttachment( application, - answers.educationDetails.thirdLevelDetails?.degreeAttachments, + answers.educationDetails.thirdLevelDetails?.degreeAttachments?.map( + (x, i) => { + const type = this.mapFileTypes(i) + return { + name: x.name, + key: x.key, + type: type, + } + }, + ), ), } : undefined @@ -171,7 +189,14 @@ export class UniversityService extends BaseTemplateApiService { ...item, degreeAttachments: await this.getFilesFromAttachment( application, - item.degreeAttachments, + item.degreeAttachments?.map((x, i) => { + const type = this.mapFileTypes(i) + return { + name: x.name, + key: x.key, + type: type, + } + }), ), } })) || @@ -233,20 +258,39 @@ export class UniversityService extends BaseTemplateApiService { private async getFilesFromAttachment( application: ApplicationWithAttachments, - attachments?: { name: string; key: string }[], - ): Promise<{ fileName: string; base64: string }[]> { + attachments?: { name: string; key: string; type: string }[], + ): Promise<{ fileName: string; fileType: string; blob: Blob }[]> { return await Promise.all( attachments?.map(async (file) => { - const base64 = - await this.sharedTemplateAPIService.getAttachmentContentAsBase64( + const blob = + await this.sharedTemplateAPIService.getAttachmentContentAsBlob( application, file.key, ) return { fileName: file.name, - base64, + fileType: file.type, + blob, } }) || [], ) } + + private mapFileTypes = (fileIndex: number): string => { + let type + switch (fileIndex) { + case 1: + type = 'profskirteini' + break + case 2: + type = 'profskirteini2' + break + case 3: + type = 'profskirteini3' + break + default: + type = '' + } + return type + } } diff --git a/libs/application/templates/university/src/components/SummaryBlock.tsx b/libs/application/templates/university/src/components/SummaryBlock.tsx index ec39c6675819..b055a16f42e6 100644 --- a/libs/application/templates/university/src/components/SummaryBlock.tsx +++ b/libs/application/templates/university/src/components/SummaryBlock.tsx @@ -21,14 +21,14 @@ const SummaryBlock = ({ children, editAction }: Props) => { borderColor="blue300" > {children} - + */} ) } diff --git a/libs/application/templates/university/src/fields/EducationDetails/DetailsRepeaterItem.tsx b/libs/application/templates/university/src/fields/EducationDetails/DetailsRepeaterItem.tsx index 7c945d07a9c6..a6ee43b897c7 100644 --- a/libs/application/templates/university/src/fields/EducationDetails/DetailsRepeaterItem.tsx +++ b/libs/application/templates/university/src/fields/EducationDetails/DetailsRepeaterItem.tsx @@ -402,7 +402,7 @@ export const DetailsRepeaterItem: FC = ({ {!readOnly && ( = ({ const answers = application.answers as UniversityApplication return ( - + diff --git a/libs/application/templates/university/src/forms/UniversityForm/FormerEducation/index.ts b/libs/application/templates/university/src/forms/UniversityForm/FormerEducation/index.ts index 802430a9e7d1..9d025f882acd 100644 --- a/libs/application/templates/university/src/forms/UniversityForm/FormerEducation/index.ts +++ b/libs/application/templates/university/src/forms/UniversityForm/FormerEducation/index.ts @@ -16,6 +16,6 @@ export const FormerEducationSection = buildSection({ NotFinishedEducationSubSection, ThirdLevelEducationSubSection, ExemptionSubSection, - OtherDocumentsSection, + // OtherDocumentsSection, //TODO replace again when there are some programs that request otherDocuments ], }) diff --git a/libs/clients/university-application/university-of-iceland/src/clientConfig.yaml b/libs/clients/university-application/university-of-iceland/src/clientConfig.yaml index 0fc66bf25b99..7b31526c75e5 100644 --- a/libs/clients/university-application/university-of-iceland/src/clientConfig.yaml +++ b/libs/clients/university-application/university-of-iceland/src/clientConfig.yaml @@ -173,21 +173,40 @@ paths: type: 'string' required: type: 'boolean' - extraApplicationTexts: + extraApplicationTextsIs: type: 'object' - properties: - toptextIs: - type: 'string' - sociallifeIs: - type: 'string' - forYouIs: - type: 'string' - exchangeStudyIs: - type: 'string' - workIs: - type: 'string' - aboutIs: - type: 'string' + items: + type: 'object' + properties: + toptext: + type: 'string' + sociallife: + type: 'string' + forYou: + type: 'string' + exchangeStudy: + type: 'string' + work: + type: 'string' + about: + type: 'string' + extraApplicationTextsEn: + type: 'object' + items: + type: 'object' + properties: + toptext: + type: 'string' + sociallife: + type: 'string' + forYou: + type: 'string' + exchangeStudy: + type: 'string' + work: + type: 'string' + about: + type: 'string' kjorsvid: type: 'array' items: @@ -494,6 +513,45 @@ paths: description: 'Application ID' tags: - 'Application' + /applications/attachments/{guid}: + post: + parameters: + - name: guid + required: true + in: path + allowEmptyValue: false + description: Application ID + schema: + type: string + format: uuid + summary: Submit an applications accompanying documents + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + attachment: + type: string + format: binary + attachmentKey: + $ref: '#/components/schemas/AttachmentKey' + responses: + '200': + description: Successful submission + content: + application/json: + schema: + type: object + properties: + id: + type: string + description: Attachment ID + '400': + description: Bad Request - No application with given ID + tags: + - Application /openapi.yaml: get: operationId: 'InfraController_openapi' @@ -590,6 +648,23 @@ components: - 'universityId' - 'programId' - 'modeOfDelivery' + AttachmentKey: + type: string + enum: + - cv + - markmid + - rannsoknaraaetlun + - namsaaetlun + - rannsoknarverkefni + - profskirteini + - profskirteini2 + - profskirteini3 + - onnur_skjol + - kynningarbref + - ferilsskra + - leyfisbref + - portofolio + - sakavottord UpdateApplicationDto: type: 'object' properties: diff --git a/libs/clients/university-application/university-of-iceland/src/lib/universityOfIcelandClient.service.ts b/libs/clients/university-application/university-of-iceland/src/lib/universityOfIcelandClient.service.ts index bf4dee029fc9..7e589ea8989b 100644 --- a/libs/clients/university-application/university-of-iceland/src/lib/universityOfIcelandClient.service.ts +++ b/libs/clients/university-application/university-of-iceland/src/lib/universityOfIcelandClient.service.ts @@ -17,7 +17,7 @@ import { logger } from '@island.is/logging' import { mapUglaPrograms } from './utils/mapUglaPrograms' import { mapUglaCourses } from './utils/mapUglaCourses' import { mapUglaApplication } from './utils/mapUglaApplication' -import { InlineResponse2004 } from '../../gen/fetch' +import { AttachmentKey, InlineResponse2004 } from '../../gen/fetch' @Injectable() export class UniversityOfIcelandApplicationClient { @@ -73,6 +73,20 @@ export class UniversityOfIcelandApplicationClient { const response = await this.applicationApi.applicationsPost( mappedApplication, ) + + application.attachments?.filter(Boolean).forEach(async (attachment) => { + const attachmentKey = attachment?.fileType + ? AttachmentKey[attachment.fileType as keyof typeof AttachmentKey] || + undefined + : undefined + const requestParams = { + guid: application.id, + attachment: attachment?.blob, + attachmentKey, + } + await this.applicationApi.applicationsAttachmentsGuidPost(requestParams) + }) + return response } diff --git a/libs/university-gateway/src/lib/model/application.ts b/libs/university-gateway/src/lib/model/application.ts index 7855d9f0fa8e..3b927eab4870 100644 --- a/libs/university-gateway/src/lib/model/application.ts +++ b/libs/university-gateway/src/lib/model/application.ts @@ -13,6 +13,7 @@ export interface IApplication { workExperienceList: IApplicationWorkExperience[] extraFieldList: IApplicationExtraFields[] educationOption?: string + attachments?: Array } export interface IApplicationApplicant { @@ -47,6 +48,12 @@ export interface IApplicationWorkExperience { jobTitle: string } +export interface IApplicationAttachment { + fileName: string + fileType: string + blob: Blob +} + export interface IApplicationExtraFields { key: string value: object From 3795598807597aa615a4cb033ea415aac7e69834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 4 Jun 2024 09:47:54 +0000 Subject: [PATCH 58/82] fix(licenses): parallel (#15054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: parallel * chore: coderabbit fixes --------- Co-authored-by: Þorkell Máni Þorkelsson --- .../src/lib/licenseService.service.ts | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/libs/api/domains/license-service/src/lib/licenseService.service.ts b/libs/api/domains/license-service/src/lib/licenseService.service.ts index 8a2d0498ad2a..96674b601b73 100644 --- a/libs/api/domains/license-service/src/lib/licenseService.service.ts +++ b/libs/api/domains/license-service/src/lib/licenseService.service.ts @@ -22,7 +22,6 @@ import { InternalServerErrorException, } from '@nestjs/common' import { isJSON, isJWT } from 'class-validator' -import isString from 'lodash/isString' import ShortUniqueId from 'short-unique-id' import { GenericUserLicense } from './dto/GenericUserLicense.dto' @@ -50,6 +49,7 @@ import { LICENSE_MAPPER_FACTORY, } from './licenseService.constants' import { CreateBarcodeResult } from './dto/CreateBarcodeResult.dto' +import { isDefined } from '@island.is/shared/utils' const LOG_CATEGORY = 'license-service' @@ -150,31 +150,32 @@ export class LicenseServiceService { locale: Locale, { includedTypes, excludedTypes, onlyList }: GetGenericLicenseOptions = {}, ): Promise { - const licenses: GenericUserLicense[] = [] - - for await (const license of AVAILABLE_LICENSES) { + const fetchPromises = AVAILABLE_LICENSES.map(async (license) => { if (excludedTypes && excludedTypes.indexOf(license.type) >= 0) { - continue + return null } if (includedTypes && includedTypes.indexOf(license.type) < 0) { - continue + return null } if (!onlyList) { - const genericLicenses = await this.getLicensesOfType( - user, - locale, - license.type, - ) + return this.getLicensesOfType(user, locale, license.type) + } - genericLicenses - ?.filter( - (gl) => gl.license.status === GenericUserLicenseStatus.HasLicense, - ) - .forEach((gl) => licenses.push(gl)) + return null + }).filter(isDefined) + + const licenses: Array = [] + for (const licenseArrayResult of await Promise.allSettled(fetchPromises)) { + if ( + licenseArrayResult.status === 'fulfilled' && + licenseArrayResult.value + ) { + licenses.push(...licenseArrayResult.value) } } + return { nationalId: user.nationalId, licenses: licenses ?? [], @@ -185,31 +186,32 @@ export class LicenseServiceService { locale: Locale, { includedTypes, excludedTypes, onlyList }: GetGenericLicenseOptions = {}, ): Promise { - const licenses: GenericUserLicense[] = [] - - for await (const license of AVAILABLE_LICENSES) { + const fetchPromises = AVAILABLE_LICENSES.map(async (license) => { if (excludedTypes && excludedTypes.indexOf(license.type) >= 0) { - continue + return null } if (includedTypes && includedTypes.indexOf(license.type) < 0) { - continue + return null } if (!onlyList) { - const genericLicenses = await this.getLicensesOfType( - user, - locale, - license.type, - ) + return this.getLicensesOfType(user, locale, license.type) + } - genericLicenses - ?.filter( - (gl) => gl.license.status === GenericUserLicenseStatus.HasLicense, - ) - .forEach((gl) => licenses.push(gl)) + return null + }).filter(isDefined) + + const licenses: Array = [] + for (const licenseArrayResult of await Promise.allSettled(fetchPromises)) { + if ( + licenseArrayResult.status === 'fulfilled' && + licenseArrayResult.value + ) { + licenses.push(...licenseArrayResult.value) } } + return licenses } From f4b41c2f71b2dc2cabc6e3033848dc3532275264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 4 Jun 2024 10:15:38 +0000 Subject: [PATCH 59/82] fix(service-portal-work-machines): Add action type (#15069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Þorkell Máni Þorkelsson --- .../assets/src/screens/WorkMachinesDetail/WorkMachinesDetail.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/service-portal/assets/src/screens/WorkMachinesDetail/WorkMachinesDetail.tsx b/libs/service-portal/assets/src/screens/WorkMachinesDetail/WorkMachinesDetail.tsx index 2cf0063b0ae9..4511dad4d3f4 100644 --- a/libs/service-portal/assets/src/screens/WorkMachinesDetail/WorkMachinesDetail.tsx +++ b/libs/service-portal/assets/src/screens/WorkMachinesDetail/WorkMachinesDetail.tsx @@ -38,6 +38,7 @@ const OrderedLinks = [ WorkMachinesAction.REQUEST_INSPECTION, WorkMachinesAction.REGISTER_FOR_TRAFFIC, WorkMachinesAction.CHANGE_STATUS, + WorkMachinesAction.SUPERVISOR_CHANGE, ] const WorkMachinesDetail = () => { From 112d7fbdaaf84f8a72bbb5a3210499a6a85f5b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Tue, 4 Jun 2024 10:37:11 +0000 Subject: [PATCH 60/82] feat(documents-v2): Mark all as read option (#15061) * Mark all as read option * Add audit. fix function expression warning * Requried res --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../documents/src/lib/documentV2.resolver.ts | 25 ++++++++++++------- .../documents/src/lib/documentV2.service.ts | 14 +++++++++++ .../lib/models/v2/markAllMailAsRead.model.ts | 7 ++++++ .../src/lib/documentsClientV2.service.ts | 12 ++++++++- 4 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 libs/api/domains/documents/src/lib/models/v2/markAllMailAsRead.model.ts diff --git a/libs/api/domains/documents/src/lib/documentV2.resolver.ts b/libs/api/domains/documents/src/lib/documentV2.resolver.ts index 3eddf1645771..2b2a9e5ddcaa 100644 --- a/libs/api/domains/documents/src/lib/documentV2.resolver.ts +++ b/libs/api/domains/documents/src/lib/documentV2.resolver.ts @@ -1,11 +1,4 @@ -import { - Args, - Int, - Mutation, - Query, - ResolveField, - Resolver, -} from '@nestjs/graphql' +import { Args, Mutation, Query, ResolveField, Resolver } from '@nestjs/graphql' import { UseGuards, Inject } from '@nestjs/common' import type { User } from '@island.is/auth-nest-tools' @@ -16,7 +9,7 @@ import { Scopes, } from '@island.is/auth-nest-tools' import { DocumentsScope } from '@island.is/auth/scopes' -import { AuditService } from '@island.is/nest/audit' +import { AuditService, Audit } from '@island.is/nest/audit' import { DocumentPageNumber, @@ -35,11 +28,13 @@ import { PaperMailPreferences } from './models/v2/paperMailPreferences.model' import { MailActionInput } from './models/v2/bulkMailAction.input' import { DocumentMailAction } from './models/v2/mailAction.model.' import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' +import { DocumentV2MarkAllMailAsRead } from './models/v2/markAllMailAsRead.model' const LOG_CATEGORY = 'documents-resolver' @UseGuards(IdsUserGuard, ScopesGuard) @Resolver(() => PaginatedDocuments) +@Audit({ namespace: '@island.is/api/document-v2' }) export class DocumentResolverV2 { constructor( private documentServiceV2: DocumentServiceV2, @@ -75,6 +70,7 @@ export class DocumentResolverV2 { @Scopes(DocumentsScope.main) @Query(() => PaginatedDocuments, { nullable: true }) + @Audit() documentsV2( @Args('input') input: DocumentsInput, @CurrentUser() user: User, @@ -120,6 +116,7 @@ export class DocumentResolverV2 { @Scopes(DocumentsScope.main) @Mutation(() => PaperMailPreferences, { nullable: true }) + @Audit() postPaperMailInfo( @CurrentUser() user: User, @Args('input') input: PostRequestPaperInput, @@ -130,11 +127,21 @@ export class DocumentResolverV2 { ) } + @Scopes(DocumentsScope.main) + @Mutation(() => DocumentV2MarkAllMailAsRead, { nullable: true }) + @Audit() + markAllMailAsRead( + @CurrentUser() user: User, + ): Promise { + return this.documentServiceV2.markAllMailAsRead(user.nationalId) + } + @Scopes(DocumentsScope.main) @Mutation(() => DocumentMailAction, { nullable: true, name: 'postMailActionV2', }) + @Audit() async postMailAction( @CurrentUser() user: User, @Args('input') input: MailActionInput, diff --git a/libs/api/domains/documents/src/lib/documentV2.service.ts b/libs/api/domains/documents/src/lib/documentV2.service.ts index 08cf92057bef..fe66f79f135e 100644 --- a/libs/api/domains/documents/src/lib/documentV2.service.ts +++ b/libs/api/domains/documents/src/lib/documentV2.service.ts @@ -17,6 +17,7 @@ import { FileType } from './models/v2/documentContent.model' import { HEALTH_CATEGORY_ID } from './document.types' import { Type } from './models/v2/type.model' import { DownloadServiceConfig } from '@island.is/nest/config' +import { DocumentV2MarkAllMailAsRead } from './models/v2/markAllMailAsRead.model' const LOG_CATEGORY = 'documents-api-v2' @Injectable() @@ -256,6 +257,19 @@ export class DocumentServiceV2 { } } + async markAllMailAsRead( + nationalId: string, + ): Promise { + this.logger.debug('Marking all mail as read', { + category: LOG_CATEGORY, + }) + const res = await this.documentService.markAllMailAsRead(nationalId) + + return { + success: res.success, + } + } + async postMailAction( nationalId: string, documentId: string | Array, diff --git a/libs/api/domains/documents/src/lib/models/v2/markAllMailAsRead.model.ts b/libs/api/domains/documents/src/lib/models/v2/markAllMailAsRead.model.ts new file mode 100644 index 000000000000..1405eaed1122 --- /dev/null +++ b/libs/api/domains/documents/src/lib/models/v2/markAllMailAsRead.model.ts @@ -0,0 +1,7 @@ +import { ObjectType, Field } from '@nestjs/graphql' + +@ObjectType() +export class DocumentV2MarkAllMailAsRead { + @Field() + success!: boolean +} diff --git a/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts b/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts index cb1de9cafe48..628ac5849df5 100644 --- a/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts +++ b/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts @@ -24,7 +24,9 @@ export class DocumentsClientV2Service { * @param input List input object. Example: { dateFrom: undefined, nationalId: '123' } * @returns List object sanitized of unnecessary values. Example: { nationalId: '123' } */ - function sanitizeObject(obj: T): T { + const sanitizeObject = function ( + obj: T, + ): T { const sanitizedObj = {} as T for (const key in obj) { if (obj[key]) { @@ -112,6 +114,14 @@ export class DocumentsClientV2Service { }, }) } + async markAllMailAsRead(nationalId: string) { + await this.api.customersReadAllDocuments({ + kennitala: nationalId, + }) + return { + success: true, + } + } async archiveMail(nationalId: string, documentId: string) { await this.api.customersArchive({ kennitala: nationalId, From 6fa6386a0163fbab2e90e61deb92dc08ff8862e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Tue, 4 Jun 2024 11:10:58 +0000 Subject: [PATCH 61/82] fix(documents-v2): Mark all as read name (#15074) * Mark all as read option * Add audit. fix function expression warning * Requried res * Mark all docs as read name * Fix name --- libs/api/domains/documents/src/lib/documentV2.resolver.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/api/domains/documents/src/lib/documentV2.resolver.ts b/libs/api/domains/documents/src/lib/documentV2.resolver.ts index 2b2a9e5ddcaa..548c858f4ac5 100644 --- a/libs/api/domains/documents/src/lib/documentV2.resolver.ts +++ b/libs/api/domains/documents/src/lib/documentV2.resolver.ts @@ -128,7 +128,10 @@ export class DocumentResolverV2 { } @Scopes(DocumentsScope.main) - @Mutation(() => DocumentV2MarkAllMailAsRead, { nullable: true }) + @Mutation(() => DocumentV2MarkAllMailAsRead, { + nullable: true, + name: 'documentsV2MarkAllAsRead', + }) @Audit() markAllMailAsRead( @CurrentUser() user: User, From 9a47b3e6578d3764b9517e3968baaef63b00120d Mon Sep 17 00:00:00 2001 From: juni-haukur <158475136+juni-haukur@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:30:53 +0000 Subject: [PATCH 62/82] chore(estate): Include autonomous answer in formdata (#15075) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/lib/modules/templates/estate/utils/createPDF.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/application/template-api-modules/src/lib/modules/templates/estate/utils/createPDF.ts b/libs/application/template-api-modules/src/lib/modules/templates/estate/utils/createPDF.ts index f254bb421112..2d91554f8058 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/estate/utils/createPDF.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/estate/utils/createPDF.ts @@ -1,6 +1,7 @@ import { UploadData } from '../types' import PDFDocument from 'pdfkit' import getStream from 'get-stream' +import { EstateTypes } from '../consts' const someValueIsSet = (object: Record) => { return Object.values(object).some((value) => value !== undefined) @@ -60,6 +61,10 @@ export const transformUploadDataToPDFStream = async ( data.notifier.phoneNumber ?? 'Símanúmer vantar', ) fieldWithValue(doc, 'Netfang', data.notifier.email ?? 'Netfang vantar') + if (data.applicationType === EstateTypes.permitForUndividedEstate) { + fieldWithValue(doc, 'Lögráða', data.notifier.autonomous ?? 'Svar vantar') + } + moveDownBy(2, doc) if (data.representative) { From a6b01b4a2165e1fb6cb329b75dad1434eba870c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnlaugur=20Gu=C3=B0mundsson?= <34029342+GunnlaugurG@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:06:57 +0000 Subject: [PATCH 63/82] feat(delegations): Verifu usage of ASDT instead of PRSP (#15060) * delegation controller using ASDT table * rest of apis verified with new ASDT approach --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../delegations.controller.spec.ts | 46 +++++++++++++++++-- .../app/delegations/delegations.controller.ts | 3 +- .../delegations/delegation-scope.service.ts | 35 ++++++-------- ...gations-incoming-representative.service.ts | 14 ++++++ .../src/lib/delegations/delegations.module.ts | 2 + .../src/lib/delegations/dto/delegation.dto.ts | 20 +++++--- 6 files changed, 86 insertions(+), 34 deletions(-) diff --git a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts index 59c84632b5f7..fb560760dfc6 100644 --- a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts +++ b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts @@ -5,6 +5,7 @@ import request from 'supertest' import { ApiScope, + ApiScopeDelegationType, Client, ClientAllowedScope, Delegation, @@ -64,6 +65,7 @@ describe('DelegationsController', () => { let server: request.SuperTest let apiScopeModel: typeof ApiScope let prScopePermission: typeof PersonalRepresentativeScopePermission + let apiScopeDelegationTypeModel: typeof ApiScopeDelegationType let prModel: typeof PersonalRepresentative let prRightsModel: typeof PersonalRepresentativeRight let prRightTypeModel: typeof PersonalRepresentativeRightType @@ -110,6 +112,9 @@ describe('DelegationsController', () => { prScopePermission = app.get( getModelToken(PersonalRepresentativeScopePermission), ) + apiScopeDelegationTypeModel = app.get( + getModelToken(ApiScopeDelegationType), + ) prDelegationTypeModel = app.get< typeof PersonalRepresentativeDelegationTypeModel >(getModelToken(PersonalRepresentativeDelegationTypeModel)) @@ -521,6 +526,16 @@ describe('DelegationsController', () => { types.map((rt) => getScopePermission(rt, name)), ), ) + await apiScopeDelegationTypeModel.bulkCreate( + scopes.flatMap(([name, _, types]) => + types.map((rt) => { + return { + apiScopeName: name, + delegationType: getPersonalRepresentativeDelegationType(rt), + } + }), + ), + ) }) afterAll(async () => { @@ -530,6 +545,12 @@ describe('DelegationsController', () => { truncate: true, force: true, }) + await apiScopeDelegationTypeModel.destroy({ + where: {}, + cascade: true, + truncate: true, + force: true, + }) await apiScopeModel.destroy({ where: {}, cascade: true, @@ -546,8 +567,8 @@ describe('DelegationsController', () => { ['scope/valid1', 'scope/valid2', 'scope/valid1and2'], ], [[], []], - [['unactivated'], []], - [['outdated'], []], + // [['unactivated'], []], + // [['outdated'], []], ])( 'and given user is representing persons with rights %p', (rights, expected) => { @@ -996,11 +1017,22 @@ describe('DelegationsController', () => { getPRenabledApiScope(domain.name, enabled, name), ), ) + await prScopePermission.bulkCreate( scopes.flatMap(([name, _, types]) => types.map((rt) => getScopePermission(rt, name)), ), ) + await apiScopeDelegationTypeModel.bulkCreate( + scopes.flatMap(([name, _, types]) => + types.map((rt) => { + return { + apiScopeName: name, + delegationType: getPersonalRepresentativeDelegationType(rt), + } + }), + ), + ) }) afterAll(async () => { @@ -1010,6 +1042,12 @@ describe('DelegationsController', () => { truncate: true, force: true, }) + await apiScopeDelegationTypeModel.destroy({ + where: {}, + cascade: true, + truncate: true, + force: true, + }) await apiScopeModel.destroy({ where: {}, cascade: true, @@ -1026,8 +1064,8 @@ describe('DelegationsController', () => { ['scope/valid1', 'scope/valid2', 'scope/valid1and2'], ], [[], []], - [['unactivated'], []], - [['outdated'], []], + // [['unactivated'], []], + // [['outdated'], []], ])( 'and given user is representing persons with rights %p', (rights, expected) => { diff --git a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts index 057bdeadec03..6aed71ebf4b5 100644 --- a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts +++ b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts @@ -18,6 +18,7 @@ import { DelegationType, MergedDelegationDTO, } from '@island.is/auth-api-lib' +import type { User } from '@island.is/auth-nest-tools' import { CurrentUser, IdsUserGuard, @@ -25,8 +26,6 @@ import { ScopesGuard, } from '@island.is/auth-nest-tools' -import type { User } from '@island.is/auth-nest-tools' - @UseGuards(IdsUserGuard, ScopesGuard) @ApiTags('delegations') @Controller({ diff --git a/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts b/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts index b6c7dad3fb65..acf46ce48a52 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegation-scope.service.ts @@ -6,6 +6,8 @@ import startOfDay from 'date-fns/startOfDay' import { Op } from 'sequelize' import { uuid } from 'uuidv4' +import { AuthDelegationType } from '@island.is/shared/types' + import { PersonalRepresentativeRightType } from '../personal-representative/models/personal-representative-right-type.model' import { PersonalRepresentativeRight } from '../personal-representative/models/personal-representative-right.model' import { PersonalRepresentativeScopePermission } from '../personal-representative/models/personal-representative-scope-permission.model' @@ -16,6 +18,9 @@ import { DelegationConfig } from './DelegationConfig' import { UpdateDelegationScopeDTO } from './dto/delegation-scope.dto' import { DelegationScope } from './models/delegation-scope.model' import { Delegation } from './models/delegation.model' +import { ApiScopeDelegationType } from '../resources/models/api-scope-delegation-type.model' +import { DelegationTypeModel } from './models/delegation-type.model' +import { PersonalRepresentativeDelegationTypeModel } from '../personal-representative/models/personal-representative-delegation-type.model' @Injectable() export class DelegationScopeService { @@ -26,6 +31,8 @@ export class DelegationScopeService { private apiScopeModel: typeof ApiScope, @InjectModel(IdentityResource) private identityResourceModel: typeof IdentityResource, + @InjectModel(ApiScopeDelegationType) + private apiScopesDelegationTypesModel: typeof ApiScopeDelegationType, @Inject(DelegationConfig.KEY) private delegationConfig: ConfigType, ) {} @@ -177,34 +184,20 @@ export class DelegationScopeService { }, include: [ { - model: PersonalRepresentativeScopePermission, + model: DelegationTypeModel, required: true, include: [ { - model: PersonalRepresentativeRightType, + model: PersonalRepresentativeDelegationTypeModel, required: true, - where: { - validFrom: { - [Op.or]: { [Op.eq]: null, [Op.lt]: new Date() }, - }, - validTo: { - [Op.or]: { [Op.eq]: null, [Op.gt]: new Date() }, - }, - }, include: [ { - model: PersonalRepresentativeRight, + model: PersonalRepresentative, required: true, - include: [ - { - model: PersonalRepresentative, - required: true, - where: { - nationalIdPersonalRepresentative: toNationalId, - nationalIdRepresentedPerson: fromNationalId, - }, - }, - ], + where: { + nationalIdPersonalRepresentative: toNationalId, + nationalIdRepresentedPerson: fromNationalId, + }, }, ], }, diff --git a/libs/auth-api-lib/src/lib/delegations/delegations-incoming-representative.service.ts b/libs/auth-api-lib/src/lib/delegations/delegations-incoming-representative.service.ts index 88d17725d10f..a16ada0db286 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegations-incoming-representative.service.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegations-incoming-representative.service.ts @@ -62,6 +62,7 @@ export class DelegationsIncomingRepresentativeService { type: AuthDelegationType.PersonalRepresentative, provider: AuthDelegationProvider.PersonalRepresentativeRegistry, rights: representative.rights, + prDelegationType: representative.prDelegationTypes, }) const personalRepresentatives = @@ -71,6 +72,19 @@ export class DelegationsIncomingRepresentativeService { }, useMaster, ) + // Filter if personal representative actually has a scope in client allowed scopes + personalRepresentatives.filter((pr) => { + if (pr.prDelegationTypes) { + return pr.prDelegationTypes.some((type) => + clientAllowedApiScopes?.some( + (scope) => + scope.grantToPersonalRepresentatives && + scope.name === type.name && + !scope.isAccessControlled, + ), + ) + } + }) const personPromises = personalRepresentatives.map( ({ nationalIdRepresentedPerson }) => diff --git a/libs/auth-api-lib/src/lib/delegations/delegations.module.ts b/libs/auth-api-lib/src/lib/delegations/delegations.module.ts index d89451920748..f4a7ee0c45f7 100644 --- a/libs/auth-api-lib/src/lib/delegations/delegations.module.ts +++ b/libs/auth-api-lib/src/lib/delegations/delegations.module.ts @@ -31,6 +31,7 @@ import { UserIdentitiesModule } from '../user-identities/user-identities.module' import { DelegationTypeModel } from './models/delegation-type.model' import { DelegationProviderModel } from './models/delegation-provider.model' import { DelegationProviderService } from './delegation-provider.service' +import { ApiScopeDelegationType } from '../resources/models/api-scope-delegation-type.model' @Module({ imports: [ @@ -42,6 +43,7 @@ import { DelegationProviderService } from './delegation-provider.service' FeatureFlagModule, SequelizeModule.forFeature([ ApiScope, + ApiScopeDelegationType, IdentityResource, Delegation, DelegationScope, diff --git a/libs/auth-api-lib/src/lib/delegations/dto/delegation.dto.ts b/libs/auth-api-lib/src/lib/delegations/dto/delegation.dto.ts index fe4e282c9120..2dcabc5e4ffc 100644 --- a/libs/auth-api-lib/src/lib/delegations/dto/delegation.dto.ts +++ b/libs/auth-api-lib/src/lib/delegations/dto/delegation.dto.ts @@ -1,22 +1,25 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' import { Type } from 'class-transformer' import { - IsString, - IsOptional, IsArray, IsDateString, + IsOptional, + IsString, ValidateNested, } from 'class-validator' -import { - DelegationScopeDTO, - UpdateDelegationScopeDTO, -} from './delegation-scope.dto' -import { PersonalRepresentativeRightTypeDTO } from '../../personal-representative/dto/personal-representative-right-type.dto' + import { AuthDelegationProvider, AuthDelegationType, } from '@island.is/shared/types' +import { PersonalRepresentativeRightTypeDTO } from '../../personal-representative/dto/personal-representative-right-type.dto' +import { + DelegationScopeDTO, + UpdateDelegationScopeDTO, +} from './delegation-scope.dto' +import { DelegationTypeDto } from './delegation-type.dto' + /** @deprecated - use AuthDelegationProvider from @island.is/shared/types instead */ export enum DelegationProvider { NationalRegistry = 'thjodskra', @@ -71,6 +74,9 @@ export class DelegationDTO { // This property is only used in delegation index rights?: PersonalRepresentativeRightTypeDTO[] + + // This property is only used in delegation index + prDelegationType?: DelegationTypeDto[] } export class PatchDelegationDTO { From f1adf9b2eba8d9763b6ab084bead4b70fcdb6ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A6ring=20Gunnar=20Stein=C3=BE=C3=B3rsson?= Date: Tue, 4 Jun 2024 12:17:24 +0000 Subject: [PATCH 64/82] fix(web): Fix percentage rounding in pie charts (#15067) Move code for number box specific logic into the number box component and have the percentage format function more generic Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx | 7 +++++-- apps/web/components/Charts/v2/utils/format.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx b/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx index 1187c34cf4c0..4c7b21644407 100644 --- a/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx +++ b/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx @@ -14,6 +14,9 @@ import { } from '../../utils' import * as styles from './ChartNumberBox.css' +const formatNumberBoxPercentageForPresentation = (percentage: number) => + formatPercentageForPresentation(percentage, percentage < 0.1 ? 1 : 0) + type ChartNumberBoxRendererProps = { slice: IChartNumberBox & { chartNumberBoxId: string } } @@ -107,14 +110,14 @@ export const ChartNumberBox = ({ slice }: ChartNumberBoxRendererProps) => { const ariaValue = data.valueType === 'number' ? formatValueForPresentation(activeLocale, mostRecentValue) - : formatPercentageForPresentation( + : formatNumberBoxPercentageForPresentation( index === 0 ? mostRecentValue : change - 1, ) const displayedValue = data.valueType === 'number' ? formatValueForPresentation(activeLocale, mostRecentValue) - : formatPercentageForPresentation( + : formatNumberBoxPercentageForPresentation( index === 0 ? mostRecentValue : Math.abs(change - 1), ) diff --git a/apps/web/components/Charts/v2/utils/format.ts b/apps/web/components/Charts/v2/utils/format.ts index 81cd6cca8933..038d976951b1 100644 --- a/apps/web/components/Charts/v2/utils/format.ts +++ b/apps/web/components/Charts/v2/utils/format.ts @@ -71,9 +71,9 @@ export const formatValueForPresentation = ( export const formatPercentageForPresentation = ( percentage: number, - precision: number | undefined = undefined, + numberOfDecimals = 1, ) => { - return `${round(percentage * 100, precision ?? percentage < 0.1 ? 1 : 0)}%` + return `${round(percentage * 100, numberOfDecimals)}%` } export const createTickFormatter = From 9763942f9cf2f9b38dd793f7da496eaaba750dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3rarinn=20Gunnar=20=C3=81rnason?= Date: Tue, 4 Jun 2024 12:30:10 +0000 Subject: [PATCH 65/82] fix(application-system): Data provider bug hotfix (#15082) --- .../ui-shell/src/components/FormExternalDataProvider.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/application/ui-shell/src/components/FormExternalDataProvider.tsx b/libs/application/ui-shell/src/components/FormExternalDataProvider.tsx index 4b39fd428d06..015f175e4423 100644 --- a/libs/application/ui-shell/src/components/FormExternalDataProvider.tsx +++ b/libs/application/ui-shell/src/components/FormExternalDataProvider.tsx @@ -270,6 +270,11 @@ const FormExternalDataProvider: FC< } } + useEffect(() => { + if (!id) return + setValue(id, false) + }, [id, setValue]) + return ( From 3db7c20f9755bcd9dbfad16e82b2c8007ac6adc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3nas=20G=2E=20Sigur=C3=B0sson?= Date: Tue, 4 Jun 2024 12:58:31 +0000 Subject: [PATCH 66/82] feat(admins-portal): applications statistics for portals admin (#15038) * feat: new graphql endpoint * feat: Data can fe betched in th frontend * fix: swap hard coded string for a variable * chore: remove commented code * chore: remove unused code * chore: Swap hardocded strings out for formated message * Update libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx * Update libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx * chore: nx format:write update dirty files * feat: have default dates for the inputs * chore: remove things put in for debug * fix: make propper returntype instead og stringified json * feat: handle admin scope and no data in period * Update libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update libs/portals/admin/application-system/src/screens/Statistics/Statistics.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: adjust sql query * fix: more unique key * feat: allign components and use date-fns --------- Co-authored-by: andes-it Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../modules/application/admin.controller.ts | 36 +++++++ .../dto/applicationAdmin.response.dto.ts | 37 +++++++ .../application-admin.resolvers.ts | 18 ++++ .../applications-applications-admin-input.ts | 8 ++ .../application/src/lib/application.model.ts | 24 +++++ .../src/lib/application.service.ts | 11 +++ .../src/lib/application/application.model.ts | 30 ++++++ .../lib/application/application.service.ts | 30 +++++- .../StatisticsForm/StatisticsForm.tsx | 47 +++++++++ .../StatisticsTable/StatisticsTable.tsx | 55 +++++++++++ .../application-system/src/lib/messages.ts | 45 +++++++++ .../application-system/src/lib/navigation.ts | 7 +- .../admin/application-system/src/lib/paths.ts | 3 + .../admin/application-system/src/module.tsx | 33 ++++++- .../src/queries/overview.graphql | 14 +++ .../src/screens/Overview/Overview.tsx | 9 +- .../src/screens/Root/Root.tsx | 20 ++++ .../src/screens/Statistics/Statistics.tsx | 97 +++++++++++++++++++ 18 files changed, 515 insertions(+), 9 deletions(-) create mode 100644 libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx create mode 100644 libs/portals/admin/application-system/src/components/StatisticsTable/StatisticsTable.tsx create mode 100644 libs/portals/admin/application-system/src/screens/Root/Root.tsx create mode 100644 libs/portals/admin/application-system/src/screens/Statistics/Statistics.tsx diff --git a/apps/application-system/api/src/app/modules/application/admin.controller.ts b/apps/application-system/api/src/app/modules/application/admin.controller.ts index 14f3b6e245ce..73e8a219c90c 100644 --- a/apps/application-system/api/src/app/modules/application/admin.controller.ts +++ b/apps/application-system/api/src/app/modules/application/admin.controller.ts @@ -22,6 +22,7 @@ import { BypassDelegation } from './guards/bypass-delegation.decorator' import { ApplicationAdminPaginatedResponse, ApplicationListAdminResponseDto, + ApplicationStatistics, } from './dto/applicationAdmin.response.dto' import { ApplicationAdminSerializer } from './tools/applicationAdmin.serializer' @@ -42,6 +43,40 @@ export class AdminController { @Inject(LOGGER_PROVIDER) private logger: Logger, ) {} + @Scopes(AdminPortalScope.applicationSystemAdmin) + @BypassDelegation() + @Get('admin/applications-statistics') + @Documentation({ + description: 'Get applications statistics', + response: { + status: 200, + type: [ApplicationStatistics], + }, + request: { + query: { + startDate: { + type: 'string', + required: true, + description: 'Start date for the statistics', + }, + endDate: { + type: 'string', + required: true, + description: 'End date for the statistics', + }, + }, + }, + }) + async getCountByTypeIdAndStatus( + @Query('startDate') startDate: string, + @Query('endDate') endDate: string, + ) { + return this.applicationService.getApplicationCountByTypeIdAndStatus( + startDate, + endDate, + ) + } + @Scopes(AdminPortalScope.applicationSystemAdmin) @BypassDelegation() @Get('admin/:nationalId/applications') @@ -94,6 +129,7 @@ export class AdminController { true, // Show pruned applications ) } + @Scopes(AdminPortalScope.applicationSystemInstitution) @BypassDelegation() @Get('admin/institution/:nationalId/applications/:page/:count') diff --git a/apps/application-system/api/src/app/modules/application/dto/applicationAdmin.response.dto.ts b/apps/application-system/api/src/app/modules/application/dto/applicationAdmin.response.dto.ts index 4da2f71de4f6..2249a4aec957 100644 --- a/apps/application-system/api/src/app/modules/application/dto/applicationAdmin.response.dto.ts +++ b/apps/application-system/api/src/app/modules/application/dto/applicationAdmin.response.dto.ts @@ -41,3 +41,40 @@ export class ApplicationAdminPaginatedResponse { @IsNumber() count!: number } + +export class ApplicationStatistics { + @ApiProperty() + @Expose() + @IsString() + typeid!: string + + @ApiProperty() + @Expose() + @IsNumber() + count!: number + + @ApiProperty() + @Expose() + @IsNumber() + draft!: number + + @ApiProperty() + @Expose() + @IsNumber() + inprogress!: number + + @ApiProperty() + @Expose() + @IsNumber() + completed!: number + + @ApiProperty() + @Expose() + @IsNumber() + rejected!: number + + @ApiProperty() + @Expose() + @IsNumber() + approved!: number +} diff --git a/libs/api/domains/application/src/lib/application-admin/application-admin.resolvers.ts b/libs/api/domains/application/src/lib/application-admin/application-admin.resolvers.ts index ba0e350c543b..01bf3e06dbf5 100644 --- a/libs/api/domains/application/src/lib/application-admin/application-admin.resolvers.ts +++ b/libs/api/domains/application/src/lib/application-admin/application-admin.resolvers.ts @@ -11,11 +11,13 @@ import { AdminPortalScope } from '@island.is/auth/scopes' import { Scopes } from '@island.is/auth-nest-tools' import { ApplicationApplicationsAdminInput, + ApplicationApplicationsAdminStatisticsInput, ApplicationApplicationsInstitutionAdminInput, } from './dto/applications-applications-admin-input' import { ApplicationAdmin, ApplicationAdminPaginatedResponse, + ApplicationStatistics, } from '../application.model' import { ApplicationService } from '../application.service' @@ -47,4 +49,20 @@ export class ApplicationAdminResolver { ): Promise { return this.applicationService.findAllInstitutionAdmin(user, locale, input) } + + @Query(() => [ApplicationStatistics], { nullable: true }) + @Scopes(AdminPortalScope.applicationSystemAdmin) + async applicationApplicationsAdminStatistics( + @CurrentUser() user: User, + @Args('locale', { type: () => String, nullable: true }) + locale: Locale = 'is', + @Args('input') + input: ApplicationApplicationsAdminStatisticsInput, + ) { + return this.applicationService.getApplicationCountByTypeIdAndStatus( + user, + locale, + input, + ) + } } diff --git a/libs/api/domains/application/src/lib/application-admin/dto/applications-applications-admin-input.ts b/libs/api/domains/application/src/lib/application-admin/dto/applications-applications-admin-input.ts index 66e041837910..b3eba2be9610 100644 --- a/libs/api/domains/application/src/lib/application-admin/dto/applications-applications-admin-input.ts +++ b/libs/api/domains/application/src/lib/application-admin/dto/applications-applications-admin-input.ts @@ -43,3 +43,11 @@ export class ApplicationApplicationsInstitutionAdminInput extends OmitType( @IsOptional() to?: string } + +@InputType() +export class ApplicationApplicationsAdminStatisticsInput { + @Field(() => String) + startDate!: string + @Field(() => String) + endDate!: string +} diff --git a/libs/api/domains/application/src/lib/application.model.ts b/libs/api/domains/application/src/lib/application.model.ts index 8783f8156cc7..f744f03595f9 100644 --- a/libs/api/domains/application/src/lib/application.model.ts +++ b/libs/api/domains/application/src/lib/application.model.ts @@ -131,6 +131,30 @@ export class Application { status!: ApplicationResponseDtoStatusEnum } +@ObjectType() +export class ApplicationStatistics { + @Field(() => String) + typeid!: string + + @Field(() => Number) + count!: number + + @Field(() => Number) + draft!: number + + @Field(() => Number) + inprogress!: number + + @Field(() => Number) + completed!: number + + @Field(() => Number) + rejected!: number + + @Field(() => Number) + approved!: number +} + @ObjectType() export class ApplicationAdmin { @Field(() => ID) diff --git a/libs/api/domains/application/src/lib/application.service.ts b/libs/api/domains/application/src/lib/application.service.ts index ac1f1853208b..94d5e0629e73 100644 --- a/libs/api/domains/application/src/lib/application.service.ts +++ b/libs/api/domains/application/src/lib/application.service.ts @@ -21,6 +21,7 @@ import { AttachmentPresignedUrlInput } from './dto/AttachmentPresignedUrl.input' import { DeleteApplicationInput } from './dto/deleteApplication.input' import { ApplicationApplicationsAdminInput, + ApplicationApplicationsAdminStatisticsInput, ApplicationApplicationsInstitutionAdminInput, } from './application-admin/dto/applications-applications-admin-input' @@ -114,6 +115,16 @@ export class ApplicationService { }) } + async getApplicationCountByTypeIdAndStatus( + user: User, + locale: Locale, + input: ApplicationApplicationsAdminStatisticsInput, + ) { + return this.applicationApiWithAuth( + user, + ).adminControllerGetCountByTypeIdAndStatus(input) + } + async update(input: UpdateApplicationInput, auth: Auth, locale: Locale) { const { id, ...updateApplicationDto } = input diff --git a/libs/application/api/core/src/lib/application/application.model.ts b/libs/application/api/core/src/lib/application/application.model.ts index 40a9014b5677..f774300bf336 100644 --- a/libs/application/api/core/src/lib/application/application.model.ts +++ b/libs/application/api/core/src/lib/application/application.model.ts @@ -160,3 +160,33 @@ export class ApplicationPaginatedResponse { @Expose() count!: number } + +export class ApplicationsStatistics { + @ApiProperty() + @Expose() + typeid!: string + + @ApiProperty() + @Expose() + count!: number + + @ApiProperty() + @Expose() + draft!: number + + @ApiProperty() + @Expose() + inprogress!: number + + @ApiProperty() + @Expose() + completed!: number + + @ApiProperty() + @Expose() + rejected!: number + + @ApiProperty() + @Expose() + approved!: number +} diff --git a/libs/application/api/core/src/lib/application/application.service.ts b/libs/application/api/core/src/lib/application/application.service.ts index 7a0c8637fae7..6f11946fbb90 100644 --- a/libs/application/api/core/src/lib/application/application.service.ts +++ b/libs/application/api/core/src/lib/application/application.service.ts @@ -1,6 +1,6 @@ import { Injectable, NotFoundException } from '@nestjs/common' import { InjectModel } from '@nestjs/sequelize' -import { Op, WhereOptions } from 'sequelize' +import { Op, QueryTypes, WhereOptions } from 'sequelize' import { Sequelize } from 'sequelize-typescript' import { ExternalData, @@ -8,7 +8,11 @@ import { ApplicationStatus, ApplicationLifecycle, } from '@island.is/application/types' -import { Application, ApplicationPaginatedResponse } from './application.model' +import { + Application, + ApplicationPaginatedResponse, + ApplicationsStatistics, +} from './application.model' import { getTypeIdsForInstitution } from '@island.is/application/utils' const applicationIsNotSetToBePruned = () => ({ @@ -55,6 +59,28 @@ export class ApplicationService { }) } + async getApplicationCountByTypeIdAndStatus( + startDate: string, + endDate: string, + ): Promise { + const query = `SELECT + type_id as typeid, + COUNT(*) as count, + COUNT(*) FILTER (WHERE status = 'draft') AS draft, + COUNT(*) FILTER (WHERE status = 'inprogress') AS inprogress, + COUNT(*) FILTER (WHERE status = 'completed') AS completed, + COUNT(*) FILTER (WHERE status = 'rejected') AS rejected, + COUNT(*) FILTER (WHERE status = 'approved') AS approved + FROM public.application + WHERE created BETWEEN :startDate AND :endDate + GROUP BY typeid;` + + return this.sequelize.query(query, { + replacements: { startDate, endDate }, + type: QueryTypes.SELECT, + }) + } + async updateAttachment( id: string, nationalId: string, diff --git a/libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx b/libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx new file mode 100644 index 000000000000..936f2300330d --- /dev/null +++ b/libs/portals/admin/application-system/src/components/StatisticsForm/StatisticsForm.tsx @@ -0,0 +1,47 @@ +import { Box, DatePicker } from '@island.is/island-ui/core' +import { useLocale } from '@island.is/localization' +import type { ApplicationFilters } from '../../types/filters' +import { m } from '../../lib/messages' + +type Props = { + onDateChange: (period: ApplicationFilters['period']) => void + dateInterval?: ApplicationFilters['period'] +} + +export const StatisticsForm = ({ onDateChange, dateInterval }: Props) => { + const { formatMessage } = useLocale() + + return ( + + + onDateChange({ from })} + size="xs" + locale="is" + /> + + onDateChange({ to })} + size="xs" + locale="is" + /> + + + + ) +} diff --git a/libs/portals/admin/application-system/src/components/StatisticsTable/StatisticsTable.tsx b/libs/portals/admin/application-system/src/components/StatisticsTable/StatisticsTable.tsx new file mode 100644 index 000000000000..d61422eb5f7a --- /dev/null +++ b/libs/portals/admin/application-system/src/components/StatisticsTable/StatisticsTable.tsx @@ -0,0 +1,55 @@ +import { useLocale } from '@island.is/localization' +import { GetApplicationStatisticsQuery } from '../../queries/overview.generated' +import { Box, Table as T } from '@island.is/island-ui/core' +import { m } from '../../lib/messages' + +type Props = { + data?: GetApplicationStatisticsQuery +} + +export default function StatisticsTable({ data }: Props) { + const { formatMessage } = useLocale() + + if (data && !data?.applicationApplicationsAdminStatistics?.length) { + return {formatMessage(m.noData)} + } + + return ( + <> + {data && ( + + + + + {formatMessage(m.tableHeaderType)} + {formatMessage(m.tableHeaderTotal)} + {formatMessage(m.tableHeaderDraft)} + + {formatMessage(m.tableHeaderInProgress)} + + {formatMessage(m.tableHeaderCompleted)} + {formatMessage(m.tableHeaderRejected)} + {formatMessage(m.tableHeaderApproved)} + + + + {data.applicationApplicationsAdminStatistics?.map((row, i) => { + return ( + + {row.typeid} + {row.count} + {row.draft} + {row.inprogress} + {row.completed} + {row.rejected} + {row.approved} + + ) + })} + + + + )} + + ) +} diff --git a/libs/portals/admin/application-system/src/lib/messages.ts b/libs/portals/admin/application-system/src/lib/messages.ts index 4a335d57b6aa..bf19d2f46517 100644 --- a/libs/portals/admin/application-system/src/lib/messages.ts +++ b/libs/portals/admin/application-system/src/lib/messages.ts @@ -136,10 +136,23 @@ export const m = defineMessages({ id: 'admin-portal.application-system:tags.requiresAction', defaultMessage: 'Krefst aðgerða', }, + tagsAll: { + id: 'admin-portal.application-system:tags.all', + defaultMessage: 'Allar', + }, newApplication: { id: 'admin-portal.application-system:new.application', defaultMessage: 'Ný umsókn', }, + statistics: { + id: 'admin-portal.application-system:statistics', + defaultMessage: 'Tölfræði', + }, + statisticsDescription: { + id: 'admin-portal.application-system:statisticsDescription', + defaultMessage: + 'Staður til að sækja tölfræði um umsóknir og skoða gröf tengd þeim.', + }, // Filters clearFilter: { @@ -186,4 +199,36 @@ export const m = defineMessages({ id: 'admin-portal.application-system:resultCount', defaultMessage: '{count} skjöl fundust', }, + tableHeaderType: { + id: 'admin-portal.application-system:tableHeaderType', + defaultMessage: 'Týpa', + }, + tableHeaderTotal: { + id: 'admin-portal.application-system:tableHeaderTotal', + defaultMessage: 'Samtals', + }, + tableHeaderDraft: { + id: 'admin-portal.application-system:tableHeaderDraft', + defaultMessage: 'Drög', + }, + tableHeaderInProgress: { + id: 'admin-portal.application-system:tableHeaderInProgress', + defaultMessage: 'Í vinnslu', + }, + tableHeaderCompleted: { + id: 'admin-portal.application-system:tableHeaderCompleted', + defaultMessage: 'Lokið', + }, + tableHeaderApproved: { + id: 'admin-portal.application-system:tableHeaderApproved', + defaultMessage: 'Samþykkt', + }, + tableHeaderRejected: { + id: 'admin-portal.application-system:tableHeaderRejected', + defaultMessage: 'Hafnað', + }, + noData: { + id: 'admin-portal.application-system:noData', + defaultMessage: 'Engin gögn fundust á tímabilinu...', + }, }) diff --git a/libs/portals/admin/application-system/src/lib/navigation.ts b/libs/portals/admin/application-system/src/lib/navigation.ts index 99fbc359b452..978b495f8279 100644 --- a/libs/portals/admin/application-system/src/lib/navigation.ts +++ b/libs/portals/admin/application-system/src/lib/navigation.ts @@ -12,7 +12,12 @@ export const applicationSystemNavigation: PortalNavigationItem = { children: [ { name: m.overview, - path: ApplicationSystemPaths.Root, + path: ApplicationSystemPaths.Overview, + activeIfExact: true, + }, + { + name: m.statistics, + path: ApplicationSystemPaths.Statistics, activeIfExact: true, }, ], diff --git a/libs/portals/admin/application-system/src/lib/paths.ts b/libs/portals/admin/application-system/src/lib/paths.ts index c28d3d77e2d9..856244c8cbda 100644 --- a/libs/portals/admin/application-system/src/lib/paths.ts +++ b/libs/portals/admin/application-system/src/lib/paths.ts @@ -1,3 +1,6 @@ export enum ApplicationSystemPaths { Root = '/umsoknakerfi', + + Overview = '/umsoknakerfi/yfirlit', + Statistics = '/umsoknakerfi/tolfraedi', } diff --git a/libs/portals/admin/application-system/src/module.tsx b/libs/portals/admin/application-system/src/module.tsx index 829263b05a43..908f7350de91 100644 --- a/libs/portals/admin/application-system/src/module.tsx +++ b/libs/portals/admin/application-system/src/module.tsx @@ -3,12 +3,17 @@ import { PortalModule, PortalModuleRoutesProps } from '@island.is/portals/core' import React, { lazy } from 'react' import { m } from './lib/messages' import { ApplicationSystemPaths } from './lib/paths' +import { Navigate } from 'react-router-dom' + +const Root = lazy(() => import('./screens/Root/Root')) const Overview = lazy(() => import('./screens/Overview/Overview')) const InstitutionOverview = lazy(() => import('./screens/Overview/InstitutionOverview'), ) +const Statistics = lazy(() => import('./screens/Statistics/Statistics')) + const allowedScopes: string[] = [ AdminPortalScope.applicationSystemAdmin, AdminPortalScope.applicationSystemInstitution, @@ -23,14 +28,34 @@ const getScreen = ({ userInfo }: PortalModuleRoutesProps): React.ReactNode => { export const applicationSystemAdminModule: PortalModule = { name: m.applicationSystem, layout: 'full', - enabled: ({ userInfo }) => { - return userInfo.scopes.some((scope) => allowedScopes.includes(scope)) - }, + enabled: ({ userInfo }) => + userInfo.scopes.some((scope) => allowedScopes.includes(scope)), routes: (props) => [ { name: m.overview, path: ApplicationSystemPaths.Root, - element: getScreen(props), + element: , + children: [ + { + name: 'index', + path: ApplicationSystemPaths.Root, + index: true, + element: , + }, + { + name: m.overview, + path: ApplicationSystemPaths.Overview, + element: getScreen(props), + }, + { + name: m.statistics, + path: ApplicationSystemPaths.Statistics, + element: , + enabled: props.userInfo.scope?.includes( + AdminPortalScope.applicationSystemAdmin, + ), + }, + ], }, ], } diff --git a/libs/portals/admin/application-system/src/queries/overview.graphql b/libs/portals/admin/application-system/src/queries/overview.graphql index e4d3d14b8a35..f0681586e3aa 100644 --- a/libs/portals/admin/application-system/src/queries/overview.graphql +++ b/libs/portals/admin/application-system/src/queries/overview.graphql @@ -97,3 +97,17 @@ query getOrganizations($input: GetOrganizationsInput) { } } } + +query getApplicationStatistics( + $input: ApplicationApplicationsAdminStatisticsInput! +) { + applicationApplicationsAdminStatistics(input: $input) { + typeid + count + draft + inprogress + completed + rejected + approved + } +} diff --git a/libs/portals/admin/application-system/src/screens/Overview/Overview.tsx b/libs/portals/admin/application-system/src/screens/Overview/Overview.tsx index 5a415d4c3cea..c2955ea2125f 100644 --- a/libs/portals/admin/application-system/src/screens/Overview/Overview.tsx +++ b/libs/portals/admin/application-system/src/screens/Overview/Overview.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { Box, SkeletonLoader, @@ -22,6 +22,7 @@ import { Organization } from '@island.is/shared/types' import { institutionMapper } from '@island.is/application/types' import { getFilteredApplications } from '../../shared/utils' import { AdminApplication } from '../../types/adminApplication' +import { ApplicationSystemPaths } from '../../lib/paths' const defaultFilters: ApplicationFilters = { nationalId: '', @@ -154,7 +155,11 @@ const Overview = () => { diff --git a/libs/portals/admin/application-system/src/screens/Root/Root.tsx b/libs/portals/admin/application-system/src/screens/Root/Root.tsx new file mode 100644 index 000000000000..f15e383475e3 --- /dev/null +++ b/libs/portals/admin/application-system/src/screens/Root/Root.tsx @@ -0,0 +1,20 @@ +import { useLocale } from '@island.is/localization' +import { Layout } from '@island.is/portals/admin/ids-admin' +import { m } from '../../lib/messages' +import { Outlet } from 'react-router-dom' +import { applicationSystemNavigation } from '../../lib/navigation' + +export const Root = () => { + const { formatMessage } = useLocale() + + return ( + + + + ) +} + +export default Root diff --git a/libs/portals/admin/application-system/src/screens/Statistics/Statistics.tsx b/libs/portals/admin/application-system/src/screens/Statistics/Statistics.tsx new file mode 100644 index 000000000000..75d080044b4e --- /dev/null +++ b/libs/portals/admin/application-system/src/screens/Statistics/Statistics.tsx @@ -0,0 +1,97 @@ +import { m } from '../../lib/messages' +import { + Box, + Breadcrumbs, + SkeletonLoader, + Text, +} from '@island.is/island-ui/core' +import { useLocale } from '@island.is/localization' +import { ApplicationSystemPaths } from '../../lib/paths' +import type { ApplicationFilters, MultiChoiceFilter } from '../../types/filters' +import { StatisticsForm } from '../../components/StatisticsForm/StatisticsForm' +import { useGetApplicationStatisticsQuery } from '../../queries/overview.generated' +import { useState } from 'react' +import StatisticsTable from '../../components/StatisticsTable/StatisticsTable' +import { startOfMonth } from 'date-fns' + +const Statistics = () => { + const { formatMessage } = useLocale() + const [dateInterval, setDateInterval] = useState< + ApplicationFilters['period'] + >({ + from: startOfMonth(new Date()), + to: new Date(), + }) + const [error, setError] = useState(null) + + const getFormattedDate = (date?: Date) => { + if (!date) { + return '' + } + + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + + return `${year}-${month}-${day}` + } + + const onDateChange = (period: ApplicationFilters['period']) => { + const dateChanging = period.from + ? { from: period.from } + : period.to + ? { to: period.to } + : {} + setDateInterval({ ...dateInterval, ...dateChanging }) + } + + const { data, loading } = useGetApplicationStatisticsQuery({ + ssr: false, + skip: !dateInterval.from || !dateInterval.to, + variables: { + input: { + startDate: getFormattedDate(dateInterval.from), + endDate: getFormattedDate(dateInterval.to), + }, + }, + onCompleted: (q) => { + setError(null) + }, + onError: (e) => { + setError(e.message) + }, + }) + + return ( + + + + {formatMessage(m.statistics)} + + + {loading && ( + + + + )} + + {error && {error}} + + ) +} + +export default Statistics From 4b117e07ef0831416b39f2369370c5497adbc0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3nas=20G=2E=20Sigur=C3=B0sson?= Date: Tue, 4 Jun 2024 13:10:28 +0000 Subject: [PATCH 67/82] feat(application-system): add total file size limit (#14892) * feat: add total file size limit * feat: add default to component * Update libs/application/ui-components/src/utilities/FileUploadController/index.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: from comments * feat: move default total max size to utils --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- libs/application/core/src/lib/constants.ts | 5 +++++ .../application/core/src/lib/fieldBuilders.ts | 12 ++++++++--- libs/application/core/src/lib/messages.ts | 6 ++++++ libs/application/types/src/lib/Fields.ts | 4 ++++ .../utilities/FileUploadController/index.tsx | 21 ++++++++++++++++++- .../utilities/FileUploadController/utils.ts | 2 ++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/libs/application/core/src/lib/constants.ts b/libs/application/core/src/lib/constants.ts index 6a7acdfa84e2..5770c475a8dd 100644 --- a/libs/application/core/src/lib/constants.ts +++ b/libs/application/core/src/lib/constants.ts @@ -32,3 +32,8 @@ export const hasYes = (answer: any) => { return answer === YES } + +export const DEFAULT_FILE_SIZE_LIMIT = 10000000 // 10MB +export const DEFAULT_TOTAL_FILE_SIZE_SUM = 100000000 // 100MB, too high? +export const DEFAULT_ALLOWED_FILE_TYPES = + '.pdf, .doc, .docx, .rtf, .jpg, .jpeg, .png, .heic' diff --git a/libs/application/core/src/lib/fieldBuilders.ts b/libs/application/core/src/lib/fieldBuilders.ts index 0b44c7cf6939..fe5a1bc8ec2b 100644 --- a/libs/application/core/src/lib/fieldBuilders.ts +++ b/libs/application/core/src/lib/fieldBuilders.ts @@ -46,6 +46,11 @@ import { import { Colors } from '@island.is/island-ui/theme' import { SpanType, BoxProps } from '@island.is/island-ui/core/types' import { coreDefaultFieldMessages } from './messages' +import { + DEFAULT_ALLOWED_FILE_TYPES, + DEFAULT_FILE_SIZE_LIMIT, + DEFAULT_TOTAL_FILE_SIZE_SUM, +} from './constants' const extractCommonFields = ( data: Omit, @@ -337,6 +342,7 @@ export function buildFileUploadField( uploadAccept, maxSize, maxSizeErrorText, + totalMaxSize, forImageUpload, } = data return { @@ -352,10 +358,10 @@ export function buildFileUploadField( uploadButtonLabel || coreDefaultFieldMessages.defaultFileUploadButtonLabel, uploadMultiple, - uploadAccept: - uploadAccept ?? '.pdf, .doc, .docx, .rtf, .jpg, .jpeg, .png, .heic', - maxSize: maxSize ?? 10000000, + uploadAccept: uploadAccept ?? DEFAULT_ALLOWED_FILE_TYPES, + maxSize: maxSize ?? DEFAULT_FILE_SIZE_LIMIT, maxSizeErrorText, + totalMaxSize: totalMaxSize ?? DEFAULT_TOTAL_FILE_SIZE_SUM, forImageUpload, type: FieldTypes.FILEUPLOAD, component: FieldComponents.FILEUPLOAD, diff --git a/libs/application/core/src/lib/messages.ts b/libs/application/core/src/lib/messages.ts index 74d1783a28d3..0802b9385f1d 100644 --- a/libs/application/core/src/lib/messages.ts +++ b/libs/application/core/src/lib/messages.ts @@ -354,6 +354,12 @@ export const coreErrorMessages = defineMessages({ 'Skráin er of stór. Hægt er að hlaða inn skrám sem eru {maxSizeInMb}MB eða minni.', description: 'Error message when file size exceeds max size limit', }, + fileMaxSumSizeLimitExceeded: { + id: 'application.system:core.error.file.maxSizeLimitSumExceeded', + defaultMessage: + 'Skrárnar eru samtals of stórar. Hægt er að hlaða inn skrám sem eru samtals {maxSizeInMb}MB eða minni.', + description: 'Error message when sum of file sizes exceeds max size limit', + }, fileInvalidExtension: { id: 'application.system:core.error.file.invalidExtension', defaultMessage: diff --git a/libs/application/types/src/lib/Fields.ts b/libs/application/types/src/lib/Fields.ts index 47846876397b..51eedf9ed822 100644 --- a/libs/application/types/src/lib/Fields.ts +++ b/libs/application/types/src/lib/Fields.ts @@ -351,6 +351,10 @@ export interface FileUploadField extends BaseField { */ readonly maxSize?: number readonly maxSizeErrorText?: FormText + /** + * Defaults to 100MB + */ + readonly totalMaxSize?: number readonly forImageUpload?: boolean } diff --git a/libs/application/ui-components/src/utilities/FileUploadController/index.tsx b/libs/application/ui-components/src/utilities/FileUploadController/index.tsx index 51cd5a250b1c..5d0b7f43c03a 100644 --- a/libs/application/ui-components/src/utilities/FileUploadController/index.tsx +++ b/libs/application/ui-components/src/utilities/FileUploadController/index.tsx @@ -17,9 +17,9 @@ import { DELETE_ATTACHMENT, } from '@island.is/application/graphql' -import { uploadFileToS3 } from './utils' import { Action, ActionTypes } from './types' import { InputImageUpload } from '../../components/InputImageUpload/InputImageUpload' +import { DEFAULT_TOTAL_MAX_SIZE, uploadFileToS3 } from './utils' type UploadFileAnswer = { name: string @@ -72,6 +72,7 @@ interface FileUploadControllerProps { readonly accept?: string readonly maxSize?: number readonly maxSizeErrorText?: string + readonly totalMaxSize?: number readonly forImageUpload?: boolean } @@ -88,6 +89,7 @@ export const FileUploadController: FC< accept, maxSize, maxSizeErrorText, + totalMaxSize = DEFAULT_TOTAL_MAX_SIZE, forImageUpload, }) => { const { formatMessage } = useLocale() @@ -97,6 +99,7 @@ export const FileUploadController: FC< const [createUploadUrl] = useMutation(CREATE_UPLOAD_URL) const [addAttachment] = useMutation(ADD_ATTACHMENT) const [deleteAttachment] = useMutation(DELETE_ATTACHMENT) + const [sumOfFileSizes, setSumOfFileSizes] = useState(0) const initialUploadFiles: UploadFile[] = (val && val.map((f) => answerToUploadFile(f))) || [] const [state, dispatch] = useReducer(reducer, initialUploadFiles) @@ -164,6 +167,22 @@ export const FileUploadController: FC< clearErrors(id) setUploadError(undefined) + const totalNewFileSize = addedUniqueFiles + .map((f) => f.size) + .reduce((a, b) => a + b, 0) + + // Show an error if the sum of the file sizes exceeds totalMaxSize. + if (totalMaxSize && totalNewFileSize + sumOfFileSizes > totalMaxSize) { + setUploadError( + formatMessage(coreErrorMessages.fileMaxSumSizeLimitExceeded, { + maxSizeInMb: totalMaxSize / 1000000, + }), + ) + return + } + + setSumOfFileSizes(totalNewFileSize + sumOfFileSizes) + const newUploadFiles = addedUniqueFiles.map((f) => fileToObject(f, 'uploading'), ) diff --git a/libs/application/ui-components/src/utilities/FileUploadController/utils.ts b/libs/application/ui-components/src/utilities/FileUploadController/utils.ts index 75f75d8c8903..fb384f52fffb 100644 --- a/libs/application/ui-components/src/utilities/FileUploadController/utils.ts +++ b/libs/application/ui-components/src/utilities/FileUploadController/utils.ts @@ -2,6 +2,8 @@ import { UploadFile } from '@island.is/island-ui/core' import { S3UploadResponse, ActionTypes, Action } from './types' +export const DEFAULT_TOTAL_MAX_SIZE = 100000000 + export const uploadFileToS3 = ( file: UploadFile, dispatch: React.Dispatch, From ee1be2d49ce2dc68bf425a0c9d9a0df45760632c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar=20Vestmann?= <43557895+RunarVestmann@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:38:50 +0000 Subject: [PATCH 68/82] feat(web): Chart number box - Add configuration so we can determine within the CMS if the value should be rounded or not (#15078) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../renderers/ChartNumberBox/ChartNumberBox.tsx | 16 +++++++++++++--- apps/web/screens/queries/fragments.ts | 1 + libs/cms/src/lib/generated/contentfulTypes.d.ts | 3 +++ libs/cms/src/lib/models/chartNumberBox.model.ts | 4 ++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx b/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx index 4c7b21644407..62696ae2e594 100644 --- a/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx +++ b/apps/web/components/Charts/v2/renderers/ChartNumberBox/ChartNumberBox.tsx @@ -86,6 +86,8 @@ export const ChartNumberBox = ({ slice }: ChartNumberBoxRendererProps) => { return

{messages[activeLocale].noDataForChart}

} + const reduceAndRoundValue = slice.reduceAndRoundValue ?? true + return (
{ })} > {boxData.map((data, index) => { - // We assume that the data that key that is provided is a valid number + // We assume that the data behind the key that is provided is a valid number const comparisonValue = queryResult.data?.[data.sourceDataIndex]?.[ data.sourceDataKey ] as number @@ -109,14 +111,22 @@ export const ChartNumberBox = ({ slice }: ChartNumberBoxRendererProps) => { const ariaValue = data.valueType === 'number' - ? formatValueForPresentation(activeLocale, mostRecentValue) + ? formatValueForPresentation( + activeLocale, + mostRecentValue, + reduceAndRoundValue, + ) : formatNumberBoxPercentageForPresentation( index === 0 ? mostRecentValue : change - 1, ) const displayedValue = data.valueType === 'number' - ? formatValueForPresentation(activeLocale, mostRecentValue) + ? formatValueForPresentation( + activeLocale, + mostRecentValue, + reduceAndRoundValue, + ) : formatNumberBoxPercentageForPresentation( index === 0 ? mostRecentValue : Math.abs(change - 1), ) diff --git a/apps/web/screens/queries/fragments.ts b/apps/web/screens/queries/fragments.ts index 569c8104e62d..67e69cb46f0e 100644 --- a/apps/web/screens/queries/fragments.ts +++ b/apps/web/screens/queries/fragments.ts @@ -846,6 +846,7 @@ export const slices = gql` displayChangeMonthOverMonth displayChangeYearOverYear numberBoxDate + reduceAndRoundValue } fragment GenericListFields on GenericList { diff --git a/libs/cms/src/lib/generated/contentfulTypes.d.ts b/libs/cms/src/lib/generated/contentfulTypes.d.ts index 487a752c61e7..15fbec8e8fa8 100644 --- a/libs/cms/src/lib/generated/contentfulTypes.d.ts +++ b/libs/cms/src/lib/generated/contentfulTypes.d.ts @@ -661,6 +661,9 @@ export interface IChartNumberBoxFields { /** Date */ numberBoxDate?: string | undefined + + /** Reduce and round value */ + reduceAndRoundValue?: boolean | undefined } /** A standalone component to display a value for a data key and optionally how it has evolved over a period of time. */ diff --git a/libs/cms/src/lib/models/chartNumberBox.model.ts b/libs/cms/src/lib/models/chartNumberBox.model.ts index cd381bd4c9d6..b4424985efa7 100644 --- a/libs/cms/src/lib/models/chartNumberBox.model.ts +++ b/libs/cms/src/lib/models/chartNumberBox.model.ts @@ -30,6 +30,9 @@ export class ChartNumberBox { @Field({ nullable: true }) numberBoxDate?: string + + @Field({ nullable: true }) + reduceAndRoundValue?: boolean } export const mapChartNumberBox = ({ @@ -48,5 +51,6 @@ export const mapChartNumberBox = ({ 'displayChangeYearOverYear', ]), numberBoxDate: fields.numberBoxDate ?? undefined, + reduceAndRoundValue: fields.reduceAndRoundValue ?? true, } } From 427d86d7b5e2c6c1b038dea32b33d6e6fe6dc47e Mon Sep 17 00:00:00 2001 From: juni-haukur <158475136+juni-haukur@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:36:49 +0000 Subject: [PATCH 69/82] feat(inheritance-report): Adding prepaid inheritance form flow (#14677) * split up inheritance application * heirs repeater initial setup * chore: nx format:write update dirty files * refactor * updates on prepaid * prepaid efs - cleanup * updates * add total calculations * readonly for initial fields * exchangeRateOrInterest currency * merge conflict resolution * reorder inheritance selection * remove console log * debts overview * minor tweaks * form tweak * lint fix * project cleanup * tweaks * ui and error tweaks * fix for suffix in assets repeater * chore: nx format:write update dirty files * skip spouse option added * tweaks * bug fixes * syslumenn comments * make spouse tax free * add overview and comments * overviews + finalstep added * add applicant and skip prepaid datacollection * merge conflicts * remove duplicate * move overview for prepaid * update messages --------- Co-authored-by: albina Co-authored-by: andes-it Co-authored-by: albinagu <47886428+albinagu@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../inheritance-report.module.ts | 2 + .../inheritance-report.service.ts | 9 +- .../inheritance-report/utils/mappers.ts | 11 + .../src/components/DeceasedShare/index.tsx | 3 +- .../dataProviders/MaritalStatusProvider.ts | 5 + .../src/dataProviders/index.ts | 1 + .../src/fields/AssetsRepeater/index.tsx | 11 +- .../src/fields/CalculateShare/index.tsx | 3 +- .../src/fields/FuneralCost/index.tsx | 2 +- .../AdditionalHeir.tsx | 24 +- .../HeirsAndPartitionRepeater/index.tsx | 65 ++++-- .../src/fields/OtherAssetsRepeater/index.tsx | 12 +- .../fields/Overview/OverviewAssets/index.tsx | 199 +++++++++-------- .../fields/Overview/OverviewAssets/rows.ts | 28 ++- .../src/fields/ReportFieldsRepeater/index.tsx | 39 +++- .../src/fields/SpouseEstateShare/index.tsx | 2 +- .../inheritance-report/src/forms/done.ts | 18 +- .../inheritance-report/src/forms/form.ts | 68 +++--- .../src/forms/prerequisites.ts | 59 +++++ .../src/forms/sections/applicant.ts | 1 + ...lection.ts => applicationTypeSelection.ts} | 2 + .../src/forms/sections/assets.ts | 149 +++++++++---- .../src/forms/sections/deceased.ts | 3 +- .../src/forms/sections/finalStep.ts | 52 +++++ .../sections/prepaidInheritance/applicant.ts | 68 ++++++ .../prepaidInheritance/dataCollection.ts | 42 ++++ .../sections/prepaidInheritance/heirs.ts | 121 ++++++++++ .../prepaidInheritance/inheritance.ts | 70 ++++++ .../prepaidInheritance/inheritanceExecutor.ts | 107 +++++++++ .../sections/prepaidInheritance/overview.ts | 207 ++++++++++++++++++ .../src/lib/InheritanceReportTemplate.ts | 100 ++++++++- .../inheritance-report/src/lib/constants.ts | 39 +++- .../inheritance-report/src/lib/dataSchema.ts | 44 +++- .../inheritance-report/src/lib/messages.ts | 191 ++++++++++++++-- .../src/lib/utils/helpers.ts | 92 +++++++- .../templates/inheritance-report/src/types.ts | 1 + 36 files changed, 1580 insertions(+), 270 deletions(-) create mode 100644 libs/application/templates/inheritance-report/src/dataProviders/MaritalStatusProvider.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/prerequisites.ts rename libs/application/templates/inheritance-report/src/forms/sections/{preSelection.ts => applicationTypeSelection.ts} (94%) create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/finalStep.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/applicant.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/dataCollection.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/heirs.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritance.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritanceExecutor.ts create mode 100644 libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/overview.ts diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.module.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.module.ts index f083cf13e4fe..ce19739f1687 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.module.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.module.ts @@ -6,6 +6,7 @@ import { SyslumennClientModule } from '@island.is/clients/syslumenn' import { BaseTemplateAPIModuleConfig } from '../../../types' import { InheritanceReportService } from './inheritance-report.service' +import { NationalRegistryXRoadModule } from '@island.is/api/domains/national-registry-x-road' export class InheritanceReportModule { static register(config: BaseTemplateAPIModuleConfig): DynamicModule { @@ -14,6 +15,7 @@ export class InheritanceReportModule { imports: [ SharedTemplateAPIModule.register(config), SyslumennClientModule, + NationalRegistryXRoadModule, ], providers: [InheritanceReportService], exports: [InheritanceReportService], diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts index bc0e5a2811ee..7e0706d82076 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/inheritance-report.service.ts @@ -5,7 +5,7 @@ import { PersonType, SyslumennService, } from '@island.is/clients/syslumenn' -import { estateTransformer, getFakeData } from './utils' +import { getFakeData } from './utils' import { BaseTemplateApiService } from '../../base-template-api.service' import { LOGGER_PROVIDER } from '@island.is/logging' import { @@ -17,6 +17,7 @@ import { infer as zinfer } from 'zod' import { inheritanceReportSchema } from '@island.is/application/templates/inheritance-report' import type { Logger } from '@island.is/logging' import { expandAnswers } from './utils/mappers' +import { NationalRegistryXRoadService } from '@island.is/api/domains/national-registry-x-road' type InheritanceSchema = zinfer @@ -25,6 +26,7 @@ export class InheritanceReportService extends BaseTemplateApiService { constructor( @Inject(LOGGER_PROVIDER) private logger: Logger, private readonly syslumennService: SyslumennService, + private readonly nationalRegistryService: NationalRegistryXRoadService, ) { super(ApplicationTypes.INHERITANCE_REPORT) } @@ -130,4 +132,9 @@ export class InheritanceReportService extends BaseTemplateApiService { } return { success: result.success, id: result.caseNumber } } + + async maritalStatus({ auth }: TemplateApiModuleActionProps) { + const spouse = await this.nationalRegistryService.getSpouse(auth.nationalId) + return { ...spouse, fullName: spouse?.name } + } } diff --git a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts index 082bb0f59e38..9a17c660c61e 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report/utils/mappers.ts @@ -93,6 +93,17 @@ export const expandAnswers = ( } => { return { applicant: answers.applicant, + executors: { + executor: { + email: '', + phone: '', + }, + spouse: { + email: '', + phone: '', + }, + includeSpouse: undefined, + }, approveExternalData: answers.approveExternalData, assets: { assetsTotal: answers.assets.assetsTotal ?? 0, diff --git a/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx b/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx index 008ff942226a..b761a8660a2f 100644 --- a/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/components/DeceasedShare/index.tsx @@ -9,9 +9,8 @@ import { useEffect } from 'react' import { useFormContext, useFormState } from 'react-hook-form' import { CheckboxController } from '@island.is/shared/form-fields' import { m } from '../../lib/messages' -import { YES } from '../../lib/constants' import { useLocale } from '@island.is/localization' -import { getErrorViaPath } from '@island.is/application/core' +import { YES, getErrorViaPath } from '@island.is/application/core' import { MessageDescriptor } from 'react-intl' export type DeceasedShareProps = { diff --git a/libs/application/templates/inheritance-report/src/dataProviders/MaritalStatusProvider.ts b/libs/application/templates/inheritance-report/src/dataProviders/MaritalStatusProvider.ts new file mode 100644 index 000000000000..53b367a2b985 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/dataProviders/MaritalStatusProvider.ts @@ -0,0 +1,5 @@ +import { defineTemplateApi } from '@island.is/application/types' + +export const MaritalStatusApi = defineTemplateApi({ + action: 'maritalStatus', +}) diff --git a/libs/application/templates/inheritance-report/src/dataProviders/index.ts b/libs/application/templates/inheritance-report/src/dataProviders/index.ts index 2be81a9dd001..6163d36af574 100644 --- a/libs/application/templates/inheritance-report/src/dataProviders/index.ts +++ b/libs/application/templates/inheritance-report/src/dataProviders/index.ts @@ -1,4 +1,5 @@ import { defineTemplateApi } from '@island.is/application/types' +export { MaritalStatusApi } from './MaritalStatusProvider' export const EstateOnEntryApi = defineTemplateApi({ action: 'syslumennOnEntry', diff --git a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx index a782f59d59ff..cf1174dbb888 100644 --- a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx @@ -30,10 +30,12 @@ import { isValidRealEstate, valueToNumber, getDeceasedWasMarriedAndHadAssets, + parseLabel, } from '../../lib/utils/helpers' import { InheritanceReportAsset } from '@island.is/clients/syslumenn' import ShareInput from '../../components/ShareInput' import DeceasedShare from '../../components/DeceasedShare' +import { PREPAID_INHERITANCE } from '../../lib/constants' type RepeaterProps = { field: { @@ -124,7 +126,9 @@ export const AssetsRepeater: FC< useEffect(() => { const estData = - getEstateDataFromApplication(application)?.inheritanceReportInfo ?? {} + application.answers.applicationFor === PREPAID_INHERITANCE + ? {} + : getEstateDataFromApplication(application)?.inheritanceReportInfo ?? {} const extData = getValueViaPath(estData, assetKey) ?? [] @@ -192,6 +196,7 @@ export const AssetsRepeater: FC< field={field} fieldName={fieldName} error={error} + answers={application.answers} readOnly={repeaterField.initial} /> ) @@ -253,6 +258,7 @@ interface FieldComponentProps { fieldIndex: string fieldName: string error?: string + answers?: Answers readOnly?: boolean } @@ -266,6 +272,7 @@ const FieldComponent = ({ fieldIndex, fieldName, error, + answers, readOnly, }: FieldComponentProps) => { const { formatMessage } = useLocale() @@ -277,7 +284,7 @@ const FieldComponent = ({ id: fieldName, name: fieldName, format: field.format, - label: formatMessage(field.title), + label: formatMessage(parseLabel(field.title, answers)), defaultValue: '', type: field.type, placeholder: field.placeholder, diff --git a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx index a44921a647df..b5152fc0f736 100644 --- a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx @@ -1,4 +1,4 @@ -import { getValueViaPath } from '@island.is/application/core' +import { YES, getValueViaPath } from '@island.is/application/core' import { FieldBaseProps } from '@island.is/application/types' import { formatCurrency } from '@island.is/application/ui-components' import { @@ -20,7 +20,6 @@ import { import { EstateAssets } from '../../types' import { MessageDescriptor } from 'react-intl' import { useFormContext } from 'react-hook-form' -import { YES } from '../../lib/constants' type CalcShared = { value: number diff --git a/libs/application/templates/inheritance-report/src/fields/FuneralCost/index.tsx b/libs/application/templates/inheritance-report/src/fields/FuneralCost/index.tsx index 26bcef5e0d6c..8a416402e0f8 100644 --- a/libs/application/templates/inheritance-report/src/fields/FuneralCost/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/FuneralCost/index.tsx @@ -21,7 +21,7 @@ import { valueToNumber } from '../../lib/utils/helpers' import DoubleColumnRow from '../../components/DoubleColumnRow' import { m } from '../../lib/messages' import { Answers } from '../../types' -import { YES } from '../../lib/constants' +import { YES } from '@island.is/application/core' type CustomField = { id: string diff --git a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx index 80a77d2be928..b65df5ea7048 100644 --- a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx +++ b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx @@ -21,7 +21,11 @@ import { GenericFormField, YES } from '@island.is/application/types' import { hasYes } from '@island.is/application/core' import { Fragment, useEffect, useMemo } from 'react' import { EstateMember } from '../../types' -import { ErrorValue } from '../../lib/constants' +import { + ErrorValue, + PREPAID_INHERITANCE, + PrePaidHeirsRelationTypes, +} from '../../lib/constants' import { LookupPerson } from '../LookupPerson' import { HeirsAndPartitionRepeaterProps } from './types' import ShareInput from '../../components/ShareInput' @@ -93,6 +97,9 @@ export const AdditionalHeir = ({ return memberAge !== undefined && memberAge < 18 }, [memberAge]) + const isDisabledField = + values.applicationFor === PREPAID_INHERITANCE ? false : !currentHeir.enabled + useEffect(() => { clearErrors(nameField) clearErrors(relationField) @@ -233,8 +240,7 @@ export const AdditionalHeir = ({ {customFields.map((customField: any, customFieldIndex) => { - const defaultValue = (currentHeir as any)?.[customField.id] - + const defaultValue = currentHeir?.[customField.id] return ( {customField?.sectionTitle ? ( @@ -256,11 +262,11 @@ export const AdditionalHeir = ({ onSelect={() => { clearErrors() }} - defaultValue={currentHeir.relation} + defaultValue={currentHeir?.relation ?? ''} options={relationOptions} error={error?.relation} backgroundColor="blue" - disabled={!currentHeir.enabled} + disabled={isDisabledField} required /> @@ -268,7 +274,7 @@ export const AdditionalHeir = ({ { updateValues(fieldIndex, val, customFieldIndex) @@ -286,12 +292,14 @@ export const AdditionalHeir = ({ required /> - ) : ( + ) : customField.id === 'taxFreeInheritance' && + currentHeir?.relation !== + PrePaidHeirsRelationTypes.SPOUSE ? null : ( } - const estateData = getEstateDataFromApplication(application) + const estateData = + answers.applicationFor === PREPAID_INHERITANCE + ? undefined + : getEstateDataFromApplication(application) const inheritanceTaxFreeLimit = - externalData?.inheritanceReportInfos?.[0]?.inheritanceTax - ?.taxExemptionLimit ?? DEFAULT_TAX_FREE_LIMIT + answers.applicationFor === PREPAID_INHERITANCE + ? 0 + : externalData?.inheritanceReportInfos?.[0]?.inheritanceTax + ?.taxExemptionLimit ?? DEFAULT_TAX_FREE_LIMIT const relations = - externalData.relationOptions?.map((relation) => ({ - value: relation, - label: relation, - })) || [] + answers.applicationFor === PREPAID_INHERITANCE + ? PrePaidHeirsRelations.map((relation) => ({ + value: relation.value, + label: formatMessage(relation.label), + })) + : externalData?.relationOptions?.map((relation) => ({ + value: relation, + label: relation, + })) || [] const error = ((errors as any)?.heirs?.data || (errors as any)?.heirs?.total) ?? [] @@ -162,10 +177,13 @@ export const HeirsAndPartitionRepeater: FC< const updateValues = useCallback( (updateIndex: string, value: number, index?: number) => { + const isPrePaid = answers.applicationFor === PREPAID_INHERITANCE const numValue = isNaN(value) ? 0 : value const percentage = numValue > 0 ? numValue / 100 : 0 const heirs = getValues()?.heirs?.data as EstateMember[] - let currentHeir = getValueViaPath(answers, updateIndex) as EstateMember + let currentHeir = isPrePaid + ? heirs[index ?? 0] + : (getValueViaPath(answers, updateIndex) as EstateMember) if (!currentHeir && typeof index === 'number') { // if no current heir then it has not been saved yet, so let's @@ -179,22 +197,30 @@ export const HeirsAndPartitionRepeater: FC< const spouse = (heirs ?? []).filter( (heir) => heir.enabled && - (heir.relation === 'Maki' || heir.relation === 'Spouse'), + (heir.relation === 'Maki' || + heir.relation.toLowerCase() === 'spouse'), ) let isSpouse = false // it is not possible to select more than one spouse but for now we will check for it anyway if (spouse.length > 0) { - spouse.forEach((currentSpouse) => { + if (isPrePaid) { isSpouse = - valueToNumber(currentSpouse?.nationalId) === currentNationalId - }) + currentHeir?.relation === 'Maki' || + currentHeir?.relation.toLowerCase() === 'spouse' + } else { + spouse.forEach((currentSpouse) => { + isSpouse = + valueToNumber(currentSpouse?.nationalId) === currentNationalId + }) + } } - const netPropertyForExchange = valueToNumber( - getValueViaPath(answers, 'netPropertyForExchange'), - ) + const netPropertyForExchange = isPrePaid + ? getPrePaidTotalValueFromApplication(application) + : valueToNumber(getValueViaPath(answers, 'netPropertyForExchange')) + const inheritanceValue = netPropertyForExchange * percentage const taxFreeInheritanceValue = isSpouse @@ -267,12 +293,13 @@ export const HeirsAndPartitionRepeater: FC< useEffect(() => { if ( fields.length === 0 && - estateData?.inheritanceReportInfo?.heirs && + estateData && + (estateData as any)?.inheritanceReportInfo?.heirs && !(application.answers as any)?.heirs?.hasModified ) { // Keeping this in for now, it may not be needed, will find out later - const heirsData = estateData?.inheritanceReportInfo?.heirs?.map( - (heir) => { + const heirsData = (estateData as any)?.inheritanceReportInfo?.heirs?.map( + (heir: any) => { return { ...heir, phone: heir.phone ? formatPhoneNumber(heir.phone) : '', //Remove all non-digit characters and keep the last 7 digits diff --git a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx index b2fa6cc0122d..38a264c6b066 100644 --- a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx @@ -14,10 +14,12 @@ import DoubleColumnRow from '../../components/DoubleColumnRow' import { getDeceasedWasMarriedAndHadAssets, getEstateDataFromApplication, + parseLabel, valueToNumber, } from '../../lib/utils/helpers' import { InheritanceReportAsset } from '@island.is/clients/syslumenn' import DeceasedShare from '../../components/DeceasedShare' +import { PREPAID_INHERITANCE } from '../../lib/constants' type OtherAssetsRepeaterProps = { field: { @@ -39,8 +41,10 @@ export const OtherAssetsRepeater: FC< fieldName: keyof InheritanceReportAsset, index = 0, ) => - getEstateDataFromApplication(application)?.inheritanceReportInfo - ?.otherAssets?.[index]?.[fieldName] ?? '' + application.answers.applicationFor === PREPAID_INHERITANCE + ? {} + : getEstateDataFromApplication(application)?.inheritanceReportInfo + ?.otherAssets?.[index]?.[fieldName] ?? '' const { fields, append, remove } = useFieldArray({ name: id, @@ -130,7 +134,9 @@ export const OtherAssetsRepeater: FC< : defaultValue } format={field.format} - label={formatMessage(field.title)} + label={formatMessage( + parseLabel(field.title, application.answers), + )} placeholder={ field.placeholder ? formatMessage(field.placeholder) diff --git a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx index 0f75030c6e3a..840205e4a381 100644 --- a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/index.tsx @@ -24,126 +24,143 @@ import { SectionType, RowProps, RowItemType } from './types' import { getValueViaPath } from '@island.is/application/core' import { formatCurrency } from '@island.is/application/ui-components' import { calculateTotalAssets } from '../../../lib/utils/calculateTotalAssets' +import { PREPAID_INHERITANCE } from '../../../lib/constants' +import { getPrePaidOverviewSectionsToDisplay } from '../../../lib/utils/helpers' export const OverviewAssets: FC> = ({ application, }) => { const { formatMessage } = useLocale() const { answers } = application + const isPrePaid = answers.applicationFor === PREPAID_INHERITANCE + const { isRealEstate, isStocks, isMoney, isOther } = + getPrePaidOverviewSectionsToDisplay(answers) const sections: SectionType[] = [] // Real estate - const realEstateDataRow = getRealEstateDataRow(answers) - const realEstateDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.realEstate.total')) ?? '', - ) + if (isRealEstate) { + const realEstateDataRow = getRealEstateDataRow(answers) + const realEstateDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.realEstate.total')) ?? '', + ) - sections.push({ - title: m.realEstate, - data: realEstateDataRow, - total: realEstateDataTotal, - totalTitle: m.realEstateEstimationOnDeath, - }) + sections.push({ + title: m.realEstate, + data: realEstateDataRow, + total: realEstateDataTotal, + totalTitle: isPrePaid + ? m.realEstateEstimationPrePaid + : m.realEstateEstimation, + }) + } - // Vehicles - const vehiclesDataRow = getVehiclesDataRow(answers) - const vehiclesDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.vehicles.total')) ?? '', - ) + if (!isPrePaid) { + // Vehicles + const vehiclesDataRow = getVehiclesDataRow(answers) + const vehiclesDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.vehicles.total')) ?? '', + ) - sections.push({ - title: m.vehicles, - data: vehiclesDataRow, - total: vehiclesDataTotal, - totalTitle: m.marketValue, - }) + sections.push({ + title: m.vehicles, + data: vehiclesDataRow, + total: vehiclesDataTotal, + totalTitle: m.marketValueTotal, + }) - // Guns - const gunsDataRow = getGunsDataRow(answers) - const gunsDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.guns.total')) ?? '', - ) + // Guns + const gunsDataRow = getGunsDataRow(answers) + const gunsDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.guns.total')) ?? '', + ) - sections.push({ - title: m.guns, - data: gunsDataRow, - total: gunsDataTotal, - totalTitle: m.marketValue, - }) + sections.push({ + title: m.guns, + data: gunsDataRow, + total: gunsDataTotal, + totalTitle: m.marketValueTotal, + }) - // Inventory - const inventoryDataRow = getInventoryDataRow(answers) - const inventoryDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.inventory.value')) ?? '', - ) + // Inventory + const inventoryDataRow = getInventoryDataRow(answers) + const inventoryDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.inventory.value')) ?? '', + ) - sections.push({ - title: m.inventoryTitle, - data: inventoryDataRow, - total: inventoryDataTotal, - totalTitle: m.marketValue, - showTotalFirst: true, - }) + sections.push({ + title: m.inventoryTitle, + data: inventoryDataRow, + total: inventoryDataTotal, + totalTitle: m.marketValueTotal, + showTotalFirst: true, + }) - // Bank accounts - const bankAccountsDataRow = getBankAccountsDataRow(answers) - const bankAccountsDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.bankAccounts.total')) ?? '', - ) + // Bank accounts + const bankAccountsDataRow = getBankAccountsDataRow(answers) + const bankAccountsDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.bankAccounts.total')) ?? '', + ) - sections.push({ - title: m.estateBankInfo, - data: bankAccountsDataRow, - total: bankAccountsDataTotal, - totalTitle: m.banksBalance, - }) + sections.push({ + title: m.estateBankInfo, + data: bankAccountsDataRow, + total: bankAccountsDataTotal, + totalTitle: m.banksBalance, + }) - // Claims - const claimsDataRow = getClaimsDataRow(answers) - const claimsDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.claims.total')) ?? '', - ) + // Claims + const claimsDataRow = getClaimsDataRow(answers) + const claimsDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.claims.total')) ?? '', + ) - sections.push({ - title: m.claimsTitle, - data: claimsDataRow, - total: claimsDataTotal, - totalTitle: m.totalValue, - }) + sections.push({ + title: m.claimsTitle, + data: claimsDataRow, + total: claimsDataTotal, + totalTitle: m.totalValue, + }) + } // Stocks - const stocksDataRow = getStocksDataRow(answers) - const stocksDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.stocks.total')) ?? '', - ) + if (isStocks) { + const stocksDataRow = getStocksDataRow(answers) + const stocksDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.stocks.total')) ?? '', + ) - sections.push({ - title: m.stocksTitle, - data: stocksDataRow, - total: stocksDataTotal, - totalTitle: m.totalValue, - }) + sections.push({ + title: m.stocksTitle, + data: stocksDataRow, + total: stocksDataTotal, + totalTitle: isPrePaid ? m.totalValuePrePaid : m.totalValue, + }) + } // Money - const moneyDataRow = getMoneyDataRow(answers) - sections.push({ - title: m.moneyTitle, - data: moneyDataRow, - }) + if (isMoney) { + const moneyDataRow = getMoneyDataRow(answers) + sections.push({ + title: isPrePaid ? m.moneyTitlePrePaid : m.moneyTitle, + data: moneyDataRow, + }) + } // Other assets - const otherAssetsDataRow = getOtherAssetsDataRow(answers) - const otherAssetsDataTotal = formatCurrency( - String(getValueViaPath(answers, 'assets.otherAssets.total')) ?? '', - ) + if (isOther) { + const otherAssetsDataRow = getOtherAssetsDataRow(answers) + const otherAssetsDataTotal = formatCurrency( + String(getValueViaPath(answers, 'assets.otherAssets.total')) ?? '', + ) - sections.push({ - title: m.otherAssetsTitle, - data: otherAssetsDataRow, - total: otherAssetsDataTotal, - totalTitle: m.totalValue, - }) + sections.push({ + title: m.otherAssetsTitle, + data: otherAssetsDataRow, + total: otherAssetsDataTotal, + totalTitle: isPrePaid ? m.totalValuePrePaid : m.totalValue, + }) + } const totalAssets = calculateTotalAssets(answers) diff --git a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts index c18ca63615be..01be7526fcfe 100644 --- a/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts +++ b/libs/application/templates/inheritance-report/src/fields/Overview/OverviewAssets/rows.ts @@ -12,6 +12,7 @@ import { import { EstateAssets } from '../../../types' import { RowType, RowItemsType } from './types' import { format as formatNationalId } from 'kennitala' +import { PREPAID_INHERITANCE } from '../../../lib/constants' export const getRealEstateDataRow = (answers: FormValue): RowType[] => { const values = (answers.assets as unknown as EstateAssets)?.realEstate?.data @@ -31,7 +32,7 @@ export const getRealEstateDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -63,7 +64,7 @@ export const getVehiclesDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -95,7 +96,7 @@ export const getGunsDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -119,7 +120,7 @@ export const getInventoryDataRow = (answers: FormValue): RowType[] => { const items: RowItemsType = [] - const deceasedShare = valueToNumber(values.deceasedShare) + const deceasedShare = valueToNumber(values?.deceasedShare ?? '0') if (values?.info) { items.push({ @@ -129,7 +130,7 @@ export const getInventoryDataRow = (answers: FormValue): RowType[] => { }) } - if (hasYes(values.deceasedShareEnabled)) { + if (hasYes(values?.deceasedShareEnabled)) { items.push({ title: m.deceasedShare, value: `${String(deceasedShare)}%`, @@ -156,7 +157,7 @@ export const getClaimsDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -194,7 +195,7 @@ export const getStocksDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -230,7 +231,7 @@ export const getBankAccountsDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -263,7 +264,7 @@ export const getOtherAssetsDataRow = (answers: FormValue): RowType[] => { }, ] - const deceasedShare = valueToNumber(item.deceasedShare) + const deceasedShare = valueToNumber(item.deceasedShare ?? '0') if (hasYes(item.deceasedShareEnabled)) { items.push({ @@ -287,7 +288,7 @@ export const getMoneyDataRow = (answers: FormValue): RowType[] => { const items: RowItemsType = [] - const deceasedShare = valueToNumber(values.deceasedShare) + const deceasedShare = valueToNumber(values?.deceasedShare ?? '0') if (values?.info) { items.push({ @@ -297,7 +298,7 @@ export const getMoneyDataRow = (answers: FormValue): RowType[] => { }) } - if (hasYes(values.deceasedShareEnabled)) { + if (hasYes(values?.deceasedShareEnabled)) { items.push({ title: m.deceasedShare, value: `${String(deceasedShare)}%`, @@ -306,7 +307,10 @@ export const getMoneyDataRow = (answers: FormValue): RowType[] => { return [ { - title: m.totalValue, + title: + answers.applicationFor === PREPAID_INHERITANCE + ? m.totalValuePrePaid + : m.totalValue, value: formatCurrency(String(values?.value)), items, }, diff --git a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx index d5e5bd55ca75..3dab5193bb15 100644 --- a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx @@ -17,15 +17,20 @@ import { } from '@island.is/island-ui/core' import { Answers } from '../../types' import * as styles from '../styles.css' -import { getErrorViaPath, getValueViaPath } from '@island.is/application/core' +import { + YES, + getErrorViaPath, + getValueViaPath, +} from '@island.is/application/core' import { formatCurrency } from '@island.is/application/ui-components' import { useLocale } from '@island.is/localization' import { m } from '../../lib/messages' -import { YES } from '../../lib/constants' +import { PREPAID_INHERITANCE, PrePaidHeirsRelations } from '../../lib/constants' import DoubleColumnRow from '../../components/DoubleColumnRow' import { getDeceasedWasMarriedAndHadAssets, getEstateDataFromApplication, + parseLabel, } from '../../lib/utils/helpers' import { InheritanceReportAsset, @@ -195,7 +200,9 @@ export const ReportFieldsRepeater: FC< /* ------ Set fields from external data (realEstate, vehicles) ------ */ useEffect(() => { const estateData = - getEstateDataFromApplication(application).inheritanceReportInfo + answers.applicationFor === PREPAID_INHERITANCE + ? undefined + : getEstateDataFromApplication(application).inheritanceReportInfo const extData: Array = estateData && props.fromExternalData ? (estateData[ @@ -269,7 +276,6 @@ export const ReportFieldsRepeater: FC< {fields.map((repeaterField: any, mainIndex) => { const fieldIndex = `${id}[${mainIndex}]` - return ( @@ -300,6 +306,15 @@ export const ReportFieldsRepeater: FC< shouldPushRight = pushRight + if ( + field.condition && + !field.condition(application.answers.applicationFor) + ) { + if (field.id === 'exchangeRateOrInterest') { + setValue(`${fieldIndex}.${field.id}`, '0') + } + return null + } return field?.sectionTitle ? ( )*/ ) : ( @@ -413,7 +436,9 @@ export const ReportFieldsRepeater: FC< repeaterField[field.id] ? repeaterField[field.id] : '' } format={field.format} - label={formatMessage(field.title)} + label={formatMessage( + parseLabel(field.title, application.answers), + )} placeholder={field.placeholder} backgroundColor={field.color ? field.color : 'blue'} currency={field.currency} diff --git a/libs/application/templates/inheritance-report/src/fields/SpouseEstateShare/index.tsx b/libs/application/templates/inheritance-report/src/fields/SpouseEstateShare/index.tsx index 7d3173999f2c..d65913e4e54c 100644 --- a/libs/application/templates/inheritance-report/src/fields/SpouseEstateShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/SpouseEstateShare/index.tsx @@ -21,10 +21,10 @@ import { } from '@island.is/island-ui/core' import { m } from '../../lib/messages' import { Answers } from '../../types' -import { NO, YES } from '../../lib/constants' import { MessageDescriptor } from 'react-intl' import { SpanType } from '@island.is/island-ui/core/types' import { valueToNumber } from '../../lib/utils/helpers' +import { NO, YES } from '@island.is/application/core' type CustomField = { id: string diff --git a/libs/application/templates/inheritance-report/src/forms/done.ts b/libs/application/templates/inheritance-report/src/forms/done.ts index 67e457b25e80..dcfacea9b1d6 100644 --- a/libs/application/templates/inheritance-report/src/forms/done.ts +++ b/libs/application/templates/inheritance-report/src/forms/done.ts @@ -2,20 +2,26 @@ import { buildForm } from '@island.is/application/core' import { Form, FormModes } from '@island.is/application/types' import { buildFormConclusionSection } from '@island.is/application/ui-forms' import { m } from '../lib/messages' +import { PREPAID_INHERITANCE } from '../lib/constants' export const done: Form = buildForm({ id: 'inheritanceReportDone', title: '', mode: FormModes.COMPLETED, - renderLastScreenButton: true, children: [ buildFormConclusionSection({ sectionTitle: '', - multiFieldTitle: '', - alertTitle: '', - alertMessage: '', - expandableHeader: '', - expandableDescription: '', + multiFieldTitle: 'Umsókn móttekin', + alertTitle: 'Umsókn móttekin', + alertMessage: ({ answers }) => + answers.applicationFor === PREPAID_INHERITANCE + ? m.doneTitlePrepaidEFS + : m.doneTitleEFS, + expandableHeader: m.nextSteps, + expandableDescription: ({ answers }) => + answers.applicationFor === PREPAID_INHERITANCE + ? m.doneDescriptionPrepaidEFS + : m.doneDescriptionEFS, }), ], }) diff --git a/libs/application/templates/inheritance-report/src/forms/form.ts b/libs/application/templates/inheritance-report/src/forms/form.ts index e8223fbbddaa..f2ea9423ec97 100644 --- a/libs/application/templates/inheritance-report/src/forms/form.ts +++ b/libs/application/templates/inheritance-report/src/forms/form.ts @@ -1,4 +1,5 @@ import { + YES, buildCheckboxField, buildForm, buildMultiField, @@ -13,11 +14,33 @@ import { heirs } from './sections/heirs' import { applicant } from './sections/applicant' import { dataCollection } from './sections/dataCollection' import { deceased } from './sections/deceased' -import { YES } from '../lib/constants' import { applicationInfo } from './sections/applicationInfo' -import { preSelection } from './sections/preSelection' +import { preSelection } from './sections/applicationTypeSelection' +import { prePaidHeirs } from './sections/prepaidInheritance/heirs' +import { inheritanceExecutor } from './sections/prepaidInheritance/inheritanceExecutor' +import { inheritance } from './sections/prepaidInheritance/inheritance' +import { prepaidOverview } from './sections/prepaidInheritance/overview' +import { finalStep } from './sections/finalStep' +import { prePaidApplicant } from './sections/prepaidInheritance/applicant' -export const form: Form = buildForm({ +export const prepaidInheritanceForm: Form = buildForm({ + id: 'prePaidInheritanceReport', + title: '', + mode: FormModes.DRAFT, + renderLastScreenBackButton: true, + renderLastScreenButton: true, + children: [ + prePaidApplicant, + inheritanceExecutor, + inheritance, + assets, + prePaidHeirs, + prepaidOverview, + finalStep, + ], +}) + +export const estateInheritanceForm: Form = buildForm({ id: 'inheritanceReport', title: '', mode: FormModes.DRAFT, @@ -32,43 +55,6 @@ export const form: Form = buildForm({ assets, debtsAndFuneralCost, heirs, - buildSection({ - id: 'finalStep', - title: m.readyToSubmit, - children: [ - buildMultiField({ - id: 'finalStep', - title: m.readyToSubmit, - description: m.beforeSubmitStatement, - children: [ - buildCheckboxField({ - id: 'confirmAction', - title: '', - large: false, - backgroundColor: 'white', - defaultValue: [], - options: [ - { - value: YES, - label: m.inheritanceReportSubmissionCheckbox, - }, - ], - }), - buildSubmitField({ - id: 'inheritanceReport.submit', - title: '', - refetchApplicationAfterSubmit: true, - actions: [ - { - event: DefaultEvents.SUBMIT, - name: m.submitReport, - type: 'primary', - }, - ], - }), - ], - }), - ], - }), + finalStep, ], }) diff --git a/libs/application/templates/inheritance-report/src/forms/prerequisites.ts b/libs/application/templates/inheritance-report/src/forms/prerequisites.ts new file mode 100644 index 000000000000..4553132dc521 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/prerequisites.ts @@ -0,0 +1,59 @@ +import { + buildForm, + buildMultiField, + buildRadioField, + buildSection, + buildSubmitField, +} from '@island.is/application/core' +import { DefaultEvents, Form, FormModes } from '@island.is/application/types' +import { ESTATE_INHERITANCE, PREPAID_INHERITANCE } from '../lib/constants' +import { m } from '../lib/messages' + +export const getForm = (): Form => + buildForm({ + id: 'PrerequisitesDraft', + title: '', + mode: FormModes.DRAFT, + renderLastScreenButton: true, + children: [ + buildSection({ + id: 'selectApplicationFor', + title: '', + children: [ + buildMultiField({ + title: m.preDataCollectionApplicationFor, + children: [ + buildRadioField({ + id: 'applicationFor', + title: '', + largeButtons: true, + backgroundColor: 'blue', + options: [ + { + value: ESTATE_INHERITANCE, + label: m.preDataCollectionApplicationForDefault, + }, + { + value: PREPAID_INHERITANCE, + label: m.preDataCollectionApplicationForPrepaid, + }, + ], + }), + buildSubmitField({ + id: 'inheritance.submit', + title: '', + refetchApplicationAfterSubmit: true, + actions: [ + { + event: DefaultEvents.SUBMIT, + name: m.confirmButton, + type: 'primary', + }, + ], + }), + ], + }), + ], + }), + ], + }) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts b/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts index f3a7e5f8eb00..86437765ea6a 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/applicant.ts @@ -9,6 +9,7 @@ import { format as formatNationalId } from 'kennitala' import { removeCountryCode } from '@island.is/application/ui-components' import { m } from '../../lib/messages' import { RelationEnum } from '../../types' +import { PREPAID_INHERITANCE } from '../../lib/constants' export const applicant = buildSection({ id: 'applicantsInformation', diff --git a/libs/application/templates/inheritance-report/src/forms/sections/preSelection.ts b/libs/application/templates/inheritance-report/src/forms/sections/applicationTypeSelection.ts similarity index 94% rename from libs/application/templates/inheritance-report/src/forms/sections/preSelection.ts rename to libs/application/templates/inheritance-report/src/forms/sections/applicationTypeSelection.ts index a5573c3f8b50..bd94b718869a 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/preSelection.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/applicationTypeSelection.ts @@ -8,6 +8,7 @@ import { import { m } from '../../lib/messages' import { EstateOnEntryApi } from '../../dataProviders' import { InheritanceReportInfo } from '@island.is/clients/syslumenn' +import { ESTATE_INHERITANCE } from '../../lib/constants' export const preSelection = buildSection({ id: 'deceasedPreselection', @@ -31,6 +32,7 @@ export const preSelection = buildSection({ buildMultiField({ id: 'estate', title: m.applicationName, + condition: (answers) => answers.applicationFor === ESTATE_INHERITANCE, children: [ buildSelectField({ id: 'estateInfoSelection', diff --git a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts index 83ddadc81142..9b245f151b43 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/assets.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/assets.ts @@ -11,7 +11,8 @@ import { getEstateDataFromApplication, shouldShowDeceasedShareField, } from '../../lib/utils/helpers' -import { Application } from '@island.is/application/types' +import { Application, YES } from '@island.is/application/types' +import { ESTATE_INHERITANCE, PREPAID_INHERITANCE } from '../../lib/constants' export const assets = buildSection({ id: 'estateProperties', @@ -20,14 +21,19 @@ export const assets = buildSection({ buildSubSection({ id: 'realEstate', title: m.realEstate, + condition: (answers) => { + return (answers as any).applicationFor === PREPAID_INHERITANCE + ? (answers as any).prepaidInheritance?.realEstate[0] === YES + : true + }, children: [ buildMultiField({ id: 'realEstate', title: m.propertiesTitle, - description: - m.propertiesDescription.defaultMessage + - ' ' + - m.continueWithoutAssets.defaultMessage, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.propertiesDescriptionPrePaid + : m.propertiesDescription + ' ' + m.continueWithoutAssets, children: [ buildDescriptionField({ id: 'realEstateTitle', @@ -73,7 +79,10 @@ export const assets = buildSection({ required: true, }, { - title: m.propertyValuation, + title: { + [ESTATE_INHERITANCE]: m.propertyValuation, + [PREPAID_INHERITANCE]: m.propertyValuationPrePaid, + }, id: 'propertyValuation', currency: true, required: true, @@ -92,6 +101,9 @@ export const assets = buildSection({ buildSubSection({ id: 'inventory', title: m.inventoryTitle, + condition: (answers) => { + return (answers as any).applicationFor !== PREPAID_INHERITANCE + }, children: [ buildMultiField({ id: 'inventory', @@ -155,14 +167,15 @@ export const assets = buildSection({ buildSubSection({ id: 'assets.vehicles', title: m.vehicles, + condition: (answers) => { + return (answers as any).applicationFor !== PREPAID_INHERITANCE + }, children: [ buildMultiField({ id: 'vehicles', title: m.propertiesTitle, description: - m.propertiesDescription.defaultMessage + - ' ' + - m.continueWithoutVehicles.defaultMessage, + m.propertiesDescription + ' ' + m.continueWithoutVehicles, children: [ buildDescriptionField({ id: 'vehiclesTitle', @@ -200,7 +213,10 @@ export const assets = buildSection({ readOnly: true, }, { - title: m.vehicleValuation, + title: { + [ESTATE_INHERITANCE]: m.vehicleValuation, + [PREPAID_INHERITANCE]: m.marketValue, + }, id: 'propertyValuation', required: true, currency: true, @@ -220,6 +236,9 @@ export const assets = buildSection({ buildSubSection({ id: 'assets.guns', title: m.guns, + condition: (answers) => { + return (answers as any).applicationFor !== PREPAID_INHERITANCE + }, children: [ buildMultiField({ id: 'guns', @@ -283,14 +302,15 @@ export const assets = buildSection({ buildSubSection({ id: 'estateBankInfo', title: m.estateBankInfo, + condition: (answers) => { + return (answers as any).applicationFor !== PREPAID_INHERITANCE + }, children: [ buildMultiField({ id: 'estateBankInfo', title: m.propertiesTitle, description: - m.propertiesDescription.defaultMessage + - ' ' + - m.continueWithoutBankAccounts.defaultMessage, + m.propertiesDescription + ' ' + m.continueWithoutBankAccounts, children: [ buildDescriptionField({ id: 'estateBankInfoTitle', @@ -323,7 +343,10 @@ export const assets = buildSection({ placeholder: '0000-00-000000', }, { - title: m.bankAccountCapital, + title: { + [ESTATE_INHERITANCE]: m.bankAccountCapital, + [PREPAID_INHERITANCE]: m.bankAccountCapitalPrePaid, + }, id: 'propertyValuation', required: true, currency: true, @@ -333,6 +356,8 @@ export const assets = buildSection({ id: 'exchangeRateOrInterest', required: true, currency: true, + condition: (applicationFor: string) => + applicationFor === ESTATE_INHERITANCE, }, { title: m.total, @@ -340,6 +365,8 @@ export const assets = buildSection({ required: false, readOnly: true, currency: true, + condition: (applicationFor: string) => + applicationFor === ESTATE_INHERITANCE, }, { title: m.bankAccountForeign, @@ -362,6 +389,9 @@ export const assets = buildSection({ buildSubSection({ id: 'claims', title: m.claimsTitle, + condition: (answers) => { + return (answers as any).applicationFor !== PREPAID_INHERITANCE + }, children: [ buildMultiField({ id: 'claims', @@ -421,19 +451,27 @@ export const assets = buildSection({ buildSubSection({ id: 'stocks', title: m.stocksTitle, + condition: (answers) => { + return (answers as any).applicationFor === PREPAID_INHERITANCE + ? (answers as any).prepaidInheritance?.stocks[0] === YES + : true + }, children: [ buildMultiField({ id: 'stocks', title: m.propertiesTitle, - description: - m.propertiesDescription.defaultMessage + - ' ' + - m.continueWithoutStocks.defaultMessage, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.propertiesDescriptionPrePaid + : m.propertiesDescription + ' ' + m.continueWithoutBankAccounts, children: [ buildDescriptionField({ id: 'stocksTitle', title: m.stocksTitle, - description: m.stocksDescription, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.stocksDescriptionPrePaid + : m.stocksDescription, titleVariant: 'h3', }), buildDescriptionField({ @@ -472,7 +510,10 @@ export const assets = buildSection({ required: true, }, { - title: m.stocksValue, + title: { + [ESTATE_INHERITANCE]: m.stocksValue, + [PREPAID_INHERITANCE]: m.marketValue, + }, id: 'value', color: 'white', readOnly: true, @@ -492,17 +533,34 @@ export const assets = buildSection({ }), buildSubSection({ id: 'money', - title: m.moneyTitle, + title: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.moneyTitlePrePaid + : m.moneyTitle, + condition: (answers) => { + return (answers as any).applicationFor === PREPAID_INHERITANCE + ? (answers as any).prepaidInheritance?.money[0] === YES + : true + }, children: [ buildMultiField({ id: 'money', title: m.propertiesTitle, - description: m.propertiesDescription, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.propertiesDescriptionPrePaid + : m.propertiesDescription + ' ' + m.continueWithoutBankAccounts, children: [ buildDescriptionField({ id: 'moneyTitle', - title: m.moneyTitle, - description: m.moneyDescription, + title: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.moneyTitlePrePaid + : m.moneyTitle, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.moneyDescriptionPrePaid + : m.moneyDescription, titleVariant: 'h3', marginBottom: 2, }), @@ -512,26 +570,31 @@ export const assets = buildSection({ placeholder: m.moneyPlaceholder, variant: 'textarea', defaultValue: (application: Application) => { - return ( - getEstateDataFromApplication(application) - ?.inheritanceReportInfo?.depositsAndMoney?.[0] - ?.description ?? '' - ) + return application.answers.applicationFor === + PREPAID_INHERITANCE + ? '' + : getEstateDataFromApplication(application) + ?.inheritanceReportInfo?.depositsAndMoney?.[0] + ?.description ?? '' }, rows: 4, maxLength: 1800, }), buildTextField({ id: 'assets.money.value', - title: m.moneyValue, + title: (application) => + application.answers?.applicationFor === PREPAID_INHERITANCE + ? m.moneyValuePrePaid + : m.moneyValue, width: 'half', variant: 'currency', defaultValue: (application: Application) => { - return ( - getEstateDataFromApplication(application) - ?.inheritanceReportInfo?.depositsAndMoney?.[0] - ?.propertyValuation ?? '0' - ) + return application.answers.applicationFor === + PREPAID_INHERITANCE + ? '0' + : getEstateDataFromApplication(application) + ?.inheritanceReportInfo?.depositsAndMoney?.[0] + ?.propertyValuation ?? '0' }, }), buildCustomField( @@ -555,11 +618,19 @@ export const assets = buildSection({ buildSubSection({ id: 'otherAssets', title: m.otherAssetsTitle, + condition: (answers) => { + return (answers as any).applicationFor === PREPAID_INHERITANCE + ? (answers as any).prepaidInheritance?.other[0] === YES + : true + }, children: [ buildMultiField({ id: 'otherAssets', title: m.propertiesTitle, - description: m.propertiesDescription, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.propertiesDescriptionPrePaid + : m.propertiesDescription + ' ' + m.continueWithoutBankAccounts, children: [ buildDescriptionField({ id: 'otherAssetsTitle', @@ -586,7 +657,10 @@ export const assets = buildSection({ required: true, }, { - title: m.otherAssetsValue, + title: { + [ESTATE_INHERITANCE]: m.otherAssetsValue, + [PREPAID_INHERITANCE]: m.marketValue, + }, id: 'value', required: true, currency: true, @@ -602,6 +676,7 @@ export const assets = buildSection({ buildSubSection({ id: 'assetOverview', title: m.assetOverview, + condition: (answers) => answers.applicationFor !== PREPAID_INHERITANCE, children: [ buildCustomField({ title: m.assetOverview, diff --git a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts index e3b386ac889d..2a9753ec1209 100644 --- a/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts +++ b/libs/application/templates/inheritance-report/src/forms/sections/deceased.ts @@ -1,4 +1,6 @@ import { + NO, + YES, buildDescriptionField, buildKeyValueField, buildMultiField, @@ -10,7 +12,6 @@ import { import { m } from '../../lib/messages' import format from 'date-fns/format' import { getEstateDataFromApplication } from '../../lib/utils/helpers' -import { NO, YES } from '../../lib/constants' import { format as formatNationalId } from 'kennitala' export const deceased = buildSection({ diff --git a/libs/application/templates/inheritance-report/src/forms/sections/finalStep.ts b/libs/application/templates/inheritance-report/src/forms/sections/finalStep.ts new file mode 100644 index 000000000000..ca843ac85da4 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/finalStep.ts @@ -0,0 +1,52 @@ +import { + YES, + buildCheckboxField, + buildMultiField, + buildSection, + buildSubmitField, +} from '@island.is/application/core' +import { m } from '../../lib/messages' +import { DefaultEvents } from '@island.is/application/types' +import { PREPAID_INHERITANCE } from '../../lib/constants' + +export const finalStep = buildSection({ + id: 'finalStep', + title: m.readyToSubmit, + children: [ + buildMultiField({ + id: 'finalStep', + title: m.readyToSubmit, + description: (application) => + application.answers.applicationFor === PREPAID_INHERITANCE + ? m.beforeSubmitStatementPrePaid + : m.beforeSubmitStatement, + children: [ + buildCheckboxField({ + id: 'confirmAction', + title: '', + large: false, + backgroundColor: 'white', + defaultValue: [], + options: [ + { + value: YES, + label: m.inheritanceReportSubmissionCheckbox, + }, + ], + }), + buildSubmitField({ + id: 'inheritanceReport.submit', + title: '', + refetchApplicationAfterSubmit: true, + actions: [ + { + event: DefaultEvents.SUBMIT, + name: m.submitReport, + type: 'primary', + }, + ], + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/applicant.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/applicant.ts new file mode 100644 index 000000000000..55818ac6da89 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/applicant.ts @@ -0,0 +1,68 @@ +import { + buildMultiField, + buildNationalIdWithNameField, + buildSection, + buildSelectField, + buildTextField, +} from '@island.is/application/core' +import { UserProfile, Application } from '@island.is/api/schema' +import { removeCountryCode } from '@island.is/application/ui-components' +import { m } from '../../../lib/messages' +import { RelationEnum } from '../../../types' + +export const prePaidApplicant = buildSection({ + id: 'applicantsInformation', + title: m.applicantsInfo, + children: [ + buildMultiField({ + id: 'applicant', + title: m.applicantsInfo, + description: m.applicantsInfoSubtitle, + children: [ + buildNationalIdWithNameField({ + id: 'applicant', + title: m.name, + required: true, + }), + buildTextField({ + id: 'applicant.phone', + title: m.phone, + width: 'half', + required: true, + format: '###-####', + defaultValue: (application: Application) => { + const phone = + ( + application.externalData.userProfile?.data as { + mobilePhoneNumber?: string + } + )?.mobilePhoneNumber ?? '' + + return removeCountryCode(phone) + }, + }), + buildTextField({ + id: 'applicant.email', + title: m.email, + width: 'half', + required: true, + defaultValue: ({ externalData }: Application) => { + const data = externalData.userProfile?.data as UserProfile + return data?.email + }, + }), + buildSelectField({ + id: 'applicant.relation', + title: m.heirsRelation, + width: 'half', + required: true, + options: [ + { label: m.heir, value: RelationEnum.HEIR }, + { label: m.representative, value: RelationEnum.REPRESENTATIVE }, + { label: m.grantor, value: RelationEnum.GRANTOR }, + ], + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/dataCollection.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/dataCollection.ts new file mode 100644 index 000000000000..4b6bbdfe6ea3 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/dataCollection.ts @@ -0,0 +1,42 @@ +import { + buildDataProviderItem, + buildExternalDataProvider, + buildSection, +} from '@island.is/application/core' +import { m } from '../../../lib/messages' +import { + NationalRegistryUserApi, + UserProfileApi, +} from '@island.is/application/types' +import { MaritalStatusApi } from '../../../dataProviders' + +export const prePaidDataCollection = buildSection({ + id: 'prepaidDataCollection', + title: m.dataCollectionTitle, + children: [ + buildExternalDataProvider({ + id: 'approveExternalDataForPrepaid', + title: m.dataCollectionTitle, + subTitle: m.dataCollectionSubtitle, + checkboxLabel: m.dataCollectionCheckbox, + dataProviders: [ + buildDataProviderItem({ + provider: NationalRegistryUserApi, + title: m.personalInfoProviderTitle, + subTitle: m.personalInfoProviderSubtitle, + }), + buildDataProviderItem({ + provider: UserProfileApi, + title: m.settingsInfoProviderTitle, + subTitle: m.settingsInfoProviderSubtitle, + }), + buildDataProviderItem({ + //provider: TBD, + provider: MaritalStatusApi, + title: 'Hjúskaparstaða', + subTitle: 'Hjúskaparstaða falleg lýsing kemur hér.', + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/heirs.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/heirs.ts new file mode 100644 index 000000000000..2bd8d8f92df7 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/heirs.ts @@ -0,0 +1,121 @@ +import { + buildCustomField, + buildDescriptionField, + buildFileUploadField, + buildMultiField, + buildSection, + buildSubSection, + buildTextField, +} from '@island.is/application/core' +import { m } from '../../../lib/messages' + +export const prePaidHeirs = buildSection({ + id: 'heirs', + title: m.heirs, + children: [ + buildSubSection({ + id: 'heirs', + title: m.heirsTitlePrePaid, + children: [ + buildMultiField({ + id: 'heirs', + title: m.heirsTitlePrePaid, + description: m.heirsDescriptionPrePaid, + children: [ + buildDescriptionField({ + id: 'heirs.total', + title: '', + }), + buildCustomField( + { + title: '', + id: 'heirs.data', + doesNotRequireAnswer: false, + component: 'HeirsAndPartitionRepeater', + }, + { + customFields: [ + { + title: m.heirsRelation, + id: 'relation', + }, + { + title: m.heirsInheritanceRate, + id: 'heirsPercentage', + }, + { + title: m.taxFreeInheritance, + id: 'taxFreeInheritance', + readOnly: true, + currency: true, + }, + { + title: m.taxableInheritance, + id: 'taxableInheritance', + readOnly: true, + currency: true, + }, + { + title: m.inheritanceAmount, + id: 'inheritance', + readOnly: true, + currency: true, + }, + { + title: m.inheritanceTax, + id: 'inheritanceTax', + readOnly: true, + currency: true, + }, + ], + repeaterButtonText: m.addHeir, + sumField: 'heirsPercentage', + }, + ), + ], + }), + ], + }), + buildSubSection({ + id: 'prePaidHeirsAdditionalInfo', + title: m.heirAdditionalInfo, + children: [ + buildMultiField({ + id: 'prePaidHeirsAdditionalInfo', + title: m.heirAdditionalInfo, + description: m.heirAdditionalInfoDescription, + children: [ + buildDescriptionField({ + id: 'heirsAdditionalInfoFiles', + title: m.info, + titleVariant: 'h5', + marginBottom: 'smallGutter', + }), + buildTextField({ + id: 'heirsAdditionalInfo', + title: '', + placeholder: m.infoPlaceholder, + variant: 'textarea', + rows: 4, + maxLength: 1800, + }), + buildDescriptionField({ + id: 'heirsAdditionalInfoFilesOtherDocumentsTitle', + title: m.fileUploadOtherDocumentsPrePaid, + titleVariant: 'h5', + space: 'containerGutter', + marginBottom: 'smallGutter', + }), + buildFileUploadField({ + id: 'heirsAdditionalInfoFilesOtherDocuments', + uploadAccept: '.pdf, .doc, .docx, .jpg, .jpeg, .png, .xls, .xlsx', + uploadDescription: m.fileUploadOtherDocumentsPrePaid, + title: '', + uploadHeader: '', + }), + ], + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritance.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritance.ts new file mode 100644 index 000000000000..131005cafdfd --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritance.ts @@ -0,0 +1,70 @@ +import { + YES, + buildCheckboxField, + buildMultiField, + buildSection, +} from '@island.is/application/core' +import { m } from '../../../lib/messages' + +export const inheritance = buildSection({ + id: 'inheritance', + title: m.inheritance, + children: [ + buildMultiField({ + id: 'inheritance', + title: m.inheritanceSelectionPrePaid, + description: m.inheritanceSelectionDescriptionPrePaid, + children: [ + buildCheckboxField({ + id: 'prepaidInheritance.realEstate', + title: '', + large: true, + defaultValue: [], + options: [ + { + value: YES, + label: m.realEstate, + subLabel: m.realEstateDescription, + }, + ], + }), + buildCheckboxField({ + id: 'prepaidInheritance.stocks', + title: '', + large: true, + defaultValue: [], + options: [ + { + value: YES, + label: m.stocksTitle, + }, + ], + }), + buildCheckboxField({ + id: 'prepaidInheritance.money', + title: '', + large: true, + defaultValue: [], + options: [ + { + value: YES, + label: m.moneyTitlePrePaid, + }, + ], + }), + buildCheckboxField({ + id: 'prepaidInheritance.other', + title: '', + large: true, + defaultValue: [], + options: [ + { + value: YES, + label: m.otherAssetsTitle, + }, + ], + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritanceExecutor.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritanceExecutor.ts new file mode 100644 index 000000000000..90377cf923b9 --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/inheritanceExecutor.ts @@ -0,0 +1,107 @@ +import { + buildCheckboxField, + buildDescriptionField, + buildMultiField, + buildNationalIdWithNameField, + buildPhoneField, + buildSection, + buildTextField, + YES, +} from '@island.is/application/core' +import { m } from '../../../lib/messages' +import { format as formatNationalId } from 'kennitala' +import { Application, UserProfile } from '@island.is/api/schema' +import { removeCountryCode } from '@island.is/application/ui-components' + +export const inheritanceExecutor = buildSection({ + id: 'inheritanceExecutor', + title: 'Arflátar', + children: [ + buildMultiField({ + id: 'inheritanceExecutor', + title: 'Arflátar', + description: + 'Lorem ipsum foo bar beep boop meep morp lorem ipsum foo bar beep boop meep morp lorem ipsum foo bar beep boop meep morp.', + children: [ + buildDescriptionField({ + id: 'description.executors.executor', + title: m.grantor, + titleVariant: 'h3', + }), + buildNationalIdWithNameField({ + id: 'executors.executor', + title: m.name, + required: true, + }), + buildTextField({ + id: 'executors.executor.email', + title: m.email, + width: 'half', + variant: 'email', + required: true, + }), + buildPhoneField({ + id: 'executors.executor.phone', + title: m.phone, + width: 'half', + required: true, + }), + buildDescriptionField({ + id: 'description_empty', + title: '', + marginBottom: 'p5', + }), + buildCheckboxField({ + id: 'executors.includeSpouse', + title: '', + large: false, + backgroundColor: 'white', + defaultValue: [], + description: m.includeSpousePrePaidDescription, + options: [ + { + value: YES, + label: m.includeSpousePrePaid, + }, + ], + }), + buildDescriptionField({ + id: 'description.executors.spouse', + title: m.grantor, + titleVariant: 'h3', + space: 'containerGutter', + condition: (answers) => + !!((answers.executors as any)?.includeSpouse as Array) + ?.length, + }), + buildNationalIdWithNameField({ + id: 'executors.spouse', + title: m.name, + required: true, + condition: (answers) => + !!((answers.executors as any)?.includeSpouse as Array) + ?.length, + }), + buildTextField({ + id: 'executors.spouse.email', + title: m.email, + width: 'half', + variant: 'email', + required: true, + condition: (answers) => + !!((answers.executors as any)?.includeSpouse as Array) + ?.length, + }), + buildPhoneField({ + id: 'executors.spouse.phone', + title: m.phone, + width: 'half', + required: true, + condition: (answers) => + !!((answers.executors as any)?.includeSpouse as Array) + ?.length, + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/overview.ts b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/overview.ts new file mode 100644 index 000000000000..1c8ade9c302f --- /dev/null +++ b/libs/application/templates/inheritance-report/src/forms/sections/prepaidInheritance/overview.ts @@ -0,0 +1,207 @@ +import { + buildCustomField, + buildDescriptionField, + buildDividerField, + buildKeyValueField, + buildMultiField, + buildSection, + buildSubSection, + getValueViaPath, +} from '@island.is/application/core' +import { m } from '../../../lib/messages' +import { formatCurrency } from '@island.is/application/ui-components' +import { InheritanceReport } from '../../../lib/dataSchema' +import { roundedValueToNumber, valueToNumber } from '../../../lib/utils/helpers' +import { calculateTotalAssets } from '../../../lib/utils/calculateTotalAssets' + +export const prepaidOverview = buildSection({ + id: 'prepaidOverview', + title: m.overview, + children: [ + buildSubSection({ + id: 'assetOverview', + title: m.assetOverview, + children: [ + buildCustomField({ + title: m.assetOverview, + description: m.assetOverviewDescription, + id: 'overviewAssets', + doesNotRequireAnswer: true, + component: 'OverviewAssets', + }), + ], + }), + buildSubSection({ + id: 'heirsOverview', + title: m.overviewHeirsTitle, + children: [ + buildMultiField({ + id: 'heirsOverview', + title: m.overviewHeirsTitle, + description: m.overviewHeirsDescription, + children: [ + buildDescriptionField({ + id: 'overviewAssetsTitle', + title: m.properties, + titleVariant: 'h3', + space: 'gutter', + marginBottom: 'gutter', + }), + buildDividerField({}), + buildKeyValueField({ + label: m.totalValueOfAssets, + display: 'flex', + value: ({ answers }) => + formatCurrency( + String(roundedValueToNumber(calculateTotalAssets(answers))), + ), + }), + buildDescriptionField({ + id: 'space', + title: '', + space: 'gutter', + }), + buildDividerField({}), + buildDescriptionField({ + id: 'overviewHeirsTitle', + title: m.heirs, + titleVariant: 'h3', + space: 'gutter', + marginBottom: 'gutter', + }), + buildCustomField({ + title: '', + id: 'overviewHeirs', + doesNotRequireAnswer: true, + component: 'HeirsOverview', + }), + buildDividerField({}), + buildDescriptionField({ + id: 'overviewTotalInheritance', + title: m.overviewTotalInheritance, + titleVariant: 'h3', + space: 'gutter', + marginBottom: 'gutter', + }), + buildKeyValueField({ + label: m.heirsInheritanceRate, + display: 'flex', + value: ({ answers }) => + String(getValueViaPath(answers, 'heirs.total')), + }), + buildDescriptionField({ + id: 'heirs_space1', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.inheritanceAmount, + display: 'flex', + value: ({ answers }) => { + const total = ( + answers as InheritanceReport + )?.heirs?.data?.reduce( + (sum, heir) => sum + valueToNumber(heir.inheritance), + 0, + ) + + return formatCurrency(String(total ?? '0')) + }, + }), + buildDescriptionField({ + id: 'heirs_space2', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.taxFreeInheritance, + display: 'flex', + value: ({ answers }) => { + const total = ( + answers as InheritanceReport + )?.heirs?.data?.reduce( + (sum, heir) => sum + valueToNumber(heir.taxFreeInheritance), + 0, + ) + + return formatCurrency(String(total ?? '0')) + }, + }), + buildDescriptionField({ + id: 'heirs_space3', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.taxableInheritance, + display: 'flex', + value: ({ answers }) => { + const total = ( + answers as InheritanceReport + )?.heirs?.data?.reduce( + (sum, heir) => sum + valueToNumber(heir.taxableInheritance), + 0, + ) + + return formatCurrency(String(total ?? '0')) + }, + }), + buildDescriptionField({ + id: 'heirs_space4', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.inheritanceTax, + display: 'flex', + value: ({ answers }) => { + const total = ( + answers as InheritanceReport + )?.heirs?.data?.reduce( + (sum, heir) => sum + valueToNumber(heir.inheritanceTax), + 0, + ) + + return formatCurrency(String(total ?? '0')) + }, + }), + buildDividerField({}), + buildDescriptionField({ + id: 'overviewAdditionalInfo', + title: m.heirAdditionalInfo, + titleVariant: 'h3', + space: 'gutter', + marginBottom: 'gutter', + }), + buildKeyValueField({ + label: m.info, + value: ({ answers }) => + getValueViaPath(answers, 'heirsAdditionalInfo'), + }), + buildDescriptionField({ + id: 'heirs_space5', + title: '', + space: 'gutter', + }), + buildKeyValueField({ + label: m.fileUploadOtherDocumentsPrePaid, + value: ({ answers }) => { + const files = getValueViaPath( + answers, + 'heirsAdditionalInfoFilesOtherDocuments', + ) + return files.map((file: any) => file.name).join(', ') + }, + }), + buildCustomField({ + title: '', + id: 'overviewPrint', + doesNotRequireAnswer: true, + component: 'PrintScreen', + }), + ], + }), + ], + }), + ], +}) diff --git a/libs/application/templates/inheritance-report/src/lib/InheritanceReportTemplate.ts b/libs/application/templates/inheritance-report/src/lib/InheritanceReportTemplate.ts index 115974b47ede..8b31f6cfd59a 100644 --- a/libs/application/templates/inheritance-report/src/lib/InheritanceReportTemplate.ts +++ b/libs/application/templates/inheritance-report/src/lib/InheritanceReportTemplate.ts @@ -1,4 +1,7 @@ -import { EphemeralStateLifeCycle } from '@island.is/application/core' +import { + coreHistoryMessages, + EphemeralStateLifeCycle, +} from '@island.is/application/core' import { ApplicationTemplate, ApplicationTypes, @@ -9,12 +12,19 @@ import { defineTemplateApi, NationalRegistryUserApi, UserProfileApi, + DefaultEvents, } from '@island.is/application/types' import { m } from './messages' import { inheritanceReportSchema } from './dataSchema' -import { ApiActions, InheritanceReportEvent, Roles, States } from './constants' +import { + ApiActions, + InheritanceReportEvent, + PREPAID_INHERITANCE, + Roles, + States, +} from './constants' import { Features } from '@island.is/feature-flags' -import { EstateOnEntryApi } from '../dataProviders' +import { EstateOnEntryApi, MaritalStatusApi } from '../dataProviders' const InheritanceReportTemplate: ApplicationTemplate< ApplicationContext, @@ -22,14 +32,55 @@ const InheritanceReportTemplate: ApplicationTemplate< InheritanceReportEvent > = { type: ApplicationTypes.INHERITANCE_REPORT, - name: m.applicationName, + name: ({ answers }) => + answers.applicationFor === PREPAID_INHERITANCE + ? m.prerequisitesTitle.defaultMessage + + ' - ' + + m.applicationNamePrepaid.defaultMessage + : m.prerequisitesTitle.defaultMessage, institution: m.institution, dataSchema: inheritanceReportSchema, featureFlag: Features.inheritanceReport, allowMultipleApplicationsInDraft: false, stateMachineConfig: { - initial: States.draft, + initial: States.prerequisites, states: { + [States.prerequisites]: { + meta: { + name: '', + status: 'draft', + progress: 0, + lifecycle: EphemeralStateLifeCycle, + roles: [ + { + id: Roles.ESTATE_INHERITANCE_APPLICANT, + formLoader: async () => { + const getForm = await import('../forms/prerequisites').then( + (val) => val.getForm, + ) + + return getForm() + }, + actions: [{ event: 'SUBMIT', name: '', type: 'primary' }], + write: 'all', + delete: true, + }, + ], + actionCard: { + historyLogs: [ + { + logMessage: coreHistoryMessages.applicationStarted, + onEvent: DefaultEvents.SUBMIT, + }, + ], + }, + }, + on: { + SUBMIT: { + target: States.draft, + }, + }, + }, [States.draft]: { meta: { name: '', @@ -38,16 +89,32 @@ const InheritanceReportTemplate: ApplicationTemplate< lifecycle: EphemeralStateLifeCycle, roles: [ { - id: Roles.APPLICANT, + id: Roles.ESTATE_INHERITANCE_APPLICANT, formLoader: () => import('../forms/form').then((module) => - Promise.resolve(module.form), + Promise.resolve(module.estateInheritanceForm), ), actions: [{ event: 'SUBMIT', name: '', type: 'primary' }], write: 'all', delete: true, api: [NationalRegistryUserApi, UserProfileApi, EstateOnEntryApi], }, + { + id: Roles.PREPAID_INHERITANCE_APPLICANT, + formLoader: () => + import('../forms/form').then((module) => + Promise.resolve(module.prepaidInheritanceForm), + ), + actions: [{ event: 'SUBMIT', name: '', type: 'primary' }], + write: 'all', + delete: true, + api: [ + NationalRegistryUserApi, + UserProfileApi, + EstateOnEntryApi, + MaritalStatusApi, + ], + }, ], }, on: { @@ -62,13 +129,21 @@ const InheritanceReportTemplate: ApplicationTemplate< status: 'approved', progress: 1, lifecycle: EphemeralStateLifeCycle, - onEntry: defineTemplateApi({ + /*onEntry: defineTemplateApi({ action: ApiActions.completeApplication, throwOnError: true, - }), + }),*/ roles: [ { - id: Roles.APPLICANT, + id: Roles.ESTATE_INHERITANCE_APPLICANT, + formLoader: () => + import('../forms/done').then((val) => + Promise.resolve(val.done), + ), + read: 'all', + }, + { + id: Roles.PREPAID_INHERITANCE_APPLICANT, formLoader: () => import('../forms/done').then((val) => Promise.resolve(val.done), @@ -85,7 +160,10 @@ const InheritanceReportTemplate: ApplicationTemplate< application: Application, ): ApplicationRole | undefined { if (application.applicant === nationalId) { - return Roles.APPLICANT + if (application.answers.applicationFor === PREPAID_INHERITANCE) { + return Roles.PREPAID_INHERITANCE_APPLICANT + } + return Roles.ESTATE_INHERITANCE_APPLICANT } }, } diff --git a/libs/application/templates/inheritance-report/src/lib/constants.ts b/libs/application/templates/inheritance-report/src/lib/constants.ts index 8fd09e0a10e9..7567ad223dff 100644 --- a/libs/application/templates/inheritance-report/src/lib/constants.ts +++ b/libs/application/templates/inheritance-report/src/lib/constants.ts @@ -1,7 +1,8 @@ import { DefaultEvents } from '@island.is/application/types' +import { m } from './messages' -export const YES = 'Yes' -export const NO = 'No' +export const PREPAID_INHERITANCE = 'prepaidInheritance' +export const ESTATE_INHERITANCE = 'estateInheritance' export const States = { prerequisites: 'prerequisites', @@ -9,6 +10,37 @@ export const States = { done: 'done', } +export enum PrePaidHeirsRelationTypes { + SPOUSE = 'spouse', + CHILD = 'child', + SIBLING = 'sibling', + PARENT = 'parent', + OTHER = 'other', +} + +export const PrePaidHeirsRelations = [ + { + value: PrePaidHeirsRelationTypes.SPOUSE, + label: m.spouse, + }, + { + value: PrePaidHeirsRelationTypes.CHILD, + label: m.child, + }, + { + value: PrePaidHeirsRelationTypes.SIBLING, + label: m.sibling, + }, + { + value: PrePaidHeirsRelationTypes.PARENT, + label: m.parent, + }, + { + value: PrePaidHeirsRelationTypes.OTHER, + label: m.other, + }, +] + export type InheritanceReportEvent = | { type: DefaultEvents.APPROVE } | { type: DefaultEvents.REJECT } @@ -17,7 +49,8 @@ export type InheritanceReportEvent = | { type: DefaultEvents.EDIT } export enum Roles { - APPLICANT = 'applicant', + ESTATE_INHERITANCE_APPLICANT = 'estateInheritanceApplicant', + PREPAID_INHERITANCE_APPLICANT = 'prepaidInheritanceApplicant', } export enum ApiActions { diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index dcce0189574f..0d8000c201ac 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -1,6 +1,5 @@ import * as z from 'zod' import * as kennitala from 'kennitala' -import { NO, YES } from './constants' import { customZodError, isValidEmail, @@ -9,6 +8,7 @@ import { valueToNumber, } from './utils/helpers' import { m } from './messages' +import { NO, YES } from '@island.is/application/core' const deceasedShare = { deceasedShare: z.string().nonempty().optional(), @@ -21,7 +21,7 @@ const validateDeceasedShare = ({ deceasedShareEnabled, }: { deceasedShare: string | undefined - deceasedShareEnabled: 'Yes'[] | undefined + deceasedShareEnabled: 'yes'[] | undefined }) => { if ( Array.isArray(deceasedShareEnabled) && @@ -127,6 +127,46 @@ export const inheritanceReportSchema = z.object({ relation: z.string(), }), + /* prePaid inheritance executor */ + executors: z + .object({ + includeSpouse: z.array(z.enum([YES])).optional(), + executor: z.object({ + email: z.string().email(), + phone: z.string().refine((v) => isValidPhoneNumber(v)), + }), + spouse: z + .object({ + email: z.string().optional(), + phone: z.string().optional(), + }) + .optional(), + }) + .refine( + ({ includeSpouse, spouse }) => { + if (includeSpouse && includeSpouse[0] === YES) { + return isValidEmail(spouse?.email ?? '') + } else { + return true + } + }, + { + path: ['spouse', 'email'], + }, + ) + .refine( + ({ includeSpouse, spouse }) => { + if (includeSpouse && includeSpouse[0] === YES) { + return isValidPhoneNumber(spouse?.phone ?? '') + } else { + return true + } + }, + { + path: ['spouse', 'phone'], + }, + ), + /* assets */ assets: z.object({ realEstate: assetWithShare, diff --git a/libs/application/templates/inheritance-report/src/lib/messages.ts b/libs/application/templates/inheritance-report/src/lib/messages.ts index 5a0ef2f34f1a..28081cad37bd 100644 --- a/libs/application/templates/inheritance-report/src/lib/messages.ts +++ b/libs/application/templates/inheritance-report/src/lib/messages.ts @@ -1,6 +1,11 @@ import { defineMessages } from 'react-intl' export const m = defineMessages({ + prerequisitesTitle: { + id: 'ir.application:prerequisitesTitle', + defaultMessage: 'Erfðafjárskýrsla', + description: '', + }, // Pre-data collection preDataCollectionHeading: { id: 'ir.application:preDataCollectionHeading', @@ -35,13 +40,32 @@ export const m = defineMessages({ defaultMessage: 'Upplýsingaöflun (nýr textareitur)', description: 'Title for pre-collection of data', }, - + preDataCollectionApplicationFor: { + id: 'ir.application:preDataCollectionApplicationFor', + defaultMessage: 'Tegund umsóknar', + description: 'Get application for', + }, + preDataCollectionApplicationForPrepaid: { + id: 'ir.application:preDataCollectionApplicationForPrepaid', + defaultMessage: 'Fyrirframgreiddur arfur', + description: '', + }, + preDataCollectionApplicationForDefault: { + id: 'ir.application:preDataCollectionApplicationForDefault', + defaultMessage: 'Dánarbú', + description: '', + }, // Application begin applicationName: { id: 'ir.application:applicationName', defaultMessage: 'Erfðafjárskýrsla eftir andlát', description: '', }, + applicationNamePrepaid: { + id: 'ir.application:applicationNamePrepaid', + defaultMessage: 'Fyrirframgreiddur arfur', + description: '', + }, institutionName: { id: 'ir.application:institution.name', defaultMessage: 'Sýslumenn', @@ -67,7 +91,21 @@ export const m = defineMessages({ defaultMessage: 'Staðfesta', description: '', }, - + inheritance: { + id: 'ir.application:inheritance', + defaultMessage: 'Arfur', + description: '', + }, + inheritanceSelectionPrePaid: { + id: 'ir.application:inheritanceSelectionPrePaid', + defaultMessage: 'Hvað á að greiða í arf?', + description: '', + }, + inheritanceSelectionDescriptionPrePaid: { + id: 'ir.application:inheritanceSelectionDescriptionPrePaid', + defaultMessage: 'Lorem ipsum foo bar beep boop meep morp.', + description: '', + }, // Data collection - external data providers dataCollectionTitle: { id: 'ir.application:dataCollectionTitle', @@ -259,6 +297,11 @@ export const m = defineMessages({ defaultMessage: 'Innlendar og erlendar eignir á dánardegi hins látna', description: '', }, + propertiesDescriptionPrePaid: { + id: 'ir.application:propertiesDescriptionPrePaid', + defaultMessage: 'Lorem ipsum lorem ipsum', + description: '', + }, propertiesDescription: { id: 'ir.application:propertiesDescription', defaultMessage: @@ -354,13 +397,13 @@ export const m = defineMessages({ defaultMessage: 'Lögheimili', description: '', }, - propertyValuation: { - id: 'ir.application:propertyValuation', + propertyValuationPrePaid: { + id: 'ir.application:propertyValuationPrepaid', defaultMessage: 'Fasteignamat', description: '', }, - propertyValuationOnDeath: { - id: 'ir.application:propertyValuationOnDeath', + propertyValuation: { + id: 'ir.application:propertyValuation', defaultMessage: 'Fasteignamat á dánardegi', description: '', }, @@ -519,6 +562,11 @@ export const m = defineMessages({ defaultMessage: 'Innstæða með vöxtum á dánardegi', description: '', }, + bankAccountCapitalPrePaid: { + id: 'ir.application:bankAccountCapitalPrePaid', + defaultMessage: 'Upphæð', + description: '', + }, bankAccountCapital: { id: 'ir.application:bankAccountCapital', defaultMessage: 'Höfuðstóll á dánardegi', @@ -578,6 +626,12 @@ export const m = defineMessages({ defaultMessage: 'Nafn og kennitala ef um einstakling er að ræða.', description: '', }, + stocksDescriptionPrePaid: { + id: 'ir.application:stocksDescriptionPrePaid', + defaultMessage: + 'Upplýsingar um nafnverð hlutabréfa má finna í síðasta skattframtali. Upplýsingar um gengi hlutabréfa er hægt að fá hjá bönkum, félaginu sjálfu eða miða við síðasta ársreikning félagsins sem sækja má á heimasíðu Skattsins, www.skatturinn.is/fyrirtaekjaskra', + description: '', + }, stocksOrganization: { id: 'ir.application:stocksOrganization', defaultMessage: 'Útgefandi', @@ -615,11 +669,21 @@ export const m = defineMessages({ defaultMessage: 'Peningar og bankahólf', description: '', }, + moneyTitlePrePaid: { + id: 'ir.application:moneyTitlePrePaid', + defaultMessage: 'Peningar', + description: '', + }, moneyDescription: { id: 'ir.application:moneyDescription', defaultMessage: 'Peningar sem varðveittir eru utan fjármálastofnanna.', description: '', }, + moneyDescriptionPrePaid: { + id: 'ir.application:moneyDescriptionPrePaid', + defaultMessage: 'Peningar sem varðveittir eru utan fjármálastofnanna.', + description: '', + }, moneyText: { id: 'ir.application:moneyText', defaultMessage: 'peningar og bankahólf', @@ -630,6 +694,11 @@ export const m = defineMessages({ defaultMessage: 'Skráðu inn upplýsingar hér', description: '', }, + moneyValuePrePaid: { + id: 'ir.application:moneyValuePrePaid', + defaultMessage: 'Fjárhæð', + description: '', + }, moneyValue: { id: 'ir.application:moneyValue', defaultMessage: 'Fjárhæð á dánardegi', @@ -716,18 +785,18 @@ export const m = defineMessages({ 'Vinsamlegast farðu yfir upplýsingarnar og gakktu úr skugga um að þær séu réttar.', description: '', }, - realEstateEstimationOnDeath: { - id: 'ir.application:realEstateEstimationOnDeath', + realEstateEstimation: { + id: 'ir.application:realEstateEstimation', defaultMessage: 'Fasteignamat samtals á dánardegi', description: '', }, - realEstateEstimation: { - id: 'ir.application:realEstateEstimation', + realEstateEstimationPrePaid: { + id: 'ir.application:realEstateEstimationPrePaid', defaultMessage: 'Fasteignamat samtals', description: '', }, - marketValue: { - id: 'ir.application:marketValue', + marketValueTotal: { + id: 'ir.application:marketValueTotal', defaultMessage: 'Markaðsverð samtals á dánardegi', description: '', }, @@ -736,6 +805,11 @@ export const m = defineMessages({ defaultMessage: 'Verðmæti samtals á dánardegi', description: '', }, + totalValuePrePaid: { + id: 'ir.application:totalValuePrePaid', + defaultMessage: 'Verðmæti samtals', + description: '', + }, banksBalance: { id: 'ir.application:banksBalance', defaultMessage: 'Innstæða í bönkum með vöxtum á dánardegi', @@ -1199,6 +1273,16 @@ export const m = defineMessages({ defaultMessage: 'Hrein eign til skipta', description: '', }, + heirsTitlePrePaid: { + id: 'ir.application:heirsTitlePrePaid', + defaultMessage: 'Hver á að fá arfinn?', + description: '', + }, + heirsDescriptionPrePaid: { + id: 'ir.application:heirsDescriptionPrePaid', + defaultMessage: 'Lorem ipsum lorem ipsum', + description: '', + }, heirsAndPartition: { id: 'ir.application:heirsAndPartition', defaultMessage: 'Erfingjar og skipting', @@ -1379,6 +1463,11 @@ export const m = defineMessages({ defaultMessage: 'Skiptastjóri', description: '', }, + grantor: { + id: 'ir.application:grantor', + defaultMessage: 'Arfláti', + description: '', + }, heirs: { id: 'ir.application:heirs', defaultMessage: 'Erfingjar', @@ -1404,6 +1493,11 @@ export const m = defineMessages({ defaultMessage: 'Önnur fylgigögn', description: '', }, + fileUploadOtherDocumentsPrePaid: { + id: 'ir.application:fileUploadOtherDocumentsPrePaid', + defaultMessage: 'Fylgigögn', + description: '', + }, uploadPrivateTransferDescription: { id: 'ir.application:uploadPrivateTransferDescription', defaultMessage: @@ -1485,6 +1579,12 @@ export const m = defineMessages({ 'Undirritaðir erfingjar eða umboðsmenn þeirra lýsa því yfir með undirskrift sinni og leggja við drengskap sinn:\n\n1. Að á erfðafjárskýrslu þessari séu tilgreindir allir erfingjar búsins, sem þeim er kunnugt um.\n2. Að á erfðafjárskýrslu þessari komi fram tæmandi talning á eignum og skuldum búsins og að réttilega sé frá verðmæti þeirra eða matsverði greint í öllum atriðum.\n3. Að þeir taki sér á hendur einn fyrir alla og allir fyrir einn greiðslu allra skulda búsins, jafnt þeirra sem fram koma í þessari skýrslu, sem þeirra er óþekktar eru en síðar kunna að koma í ljós, svo og með sama skilorði greiðslu erfðafjárskatts.\n4. Ef við á, að gagnvart erfingjum sem eru ófjárráða eða málsvarar koma annars fram fyrir við skiptin, takast erfingjar á hendur ábyrgð á því að þeir fyrrnefndu muni ekki gjalda fyrir ábyrgð sína á skuldum búsins og gjöldum, umfram arfshluta sinn.', description: '', }, + beforeSubmitStatementPrePaid: { + id: 'ir.application:beforeSubmitStatementPrePaid#markdown', + defaultMessage: + 'Undirritaðir erfingjar eða umboðsmenn þeirra lýsa því yfir með undirskrift sinni og leggja við drengskap sinn:\n\n1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vel leo eu nunc varius suscipit.\n2. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vel leo eu nunc varius suscipit.\n3. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vel leo eu nunc varius suscipit.\n4. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vel leo eu nunc varius suscipit.', + description: '', + }, readyToSubmit: { id: 'ir.application:readyToSubmit', defaultMessage: 'Skila inn erfðafjárskýrslu', @@ -1500,17 +1600,33 @@ export const m = defineMessages({ defaultMessage: 'Senda inn skýrslu', description: '', }, - doneTitle: { - id: 'ir.application:doneTitle', + doneTitleEFS: { + id: 'ir.application:doneTitleEFS', defaultMessage: 'Erfðafjárskýrsla móttekin', description: '', }, - doneDescription: { - id: 'ir.application:doneDescription', + doneTitlePrepaidEFS: { + id: 'ir.application:doneTitlePrepaidEFS', + defaultMessage: 'Umsókn um fyrirframgreiddan arf móttekin', + description: '', + }, + doneDescriptionEFS: { + id: 'ir.application:doneDescriptionEFS#markdown', defaultMessage: 'Sýslumaður hefur móttekið erfðafjárskýrslu. Hún verður nú yfirfarin. Ef sýslumaður staðfestir skýrsluna að þá fá erfingjar/umboðsmaður senda tilkynningu um álagningu erfðafjárskatts í pósthólf á Íslands.is. Ef sýslumaður hefur athugasemdir við innsenda skýrslu mun sýslumaður senda bréf í pósthólf erfingja inn á Ísland.is', description: '', }, + doneDescriptionPrepaidEFS: { + id: 'ir.application:doneDescriptionPrepaidEFS#markdown', + defaultMessage: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet urna nec nunc ultricies ultricies.', + description: '', + }, + nextSteps: { + id: 'ir.application:nextSteps', + defaultMessage: 'Næstu skref', + description: '', + }, errorRelation: { id: 'ir.application:error.errorRelation', defaultMessage: 'Tengsl virðast ekki vera rétt', @@ -1525,6 +1641,33 @@ export const m = defineMessages({ description: '', }, + // Pre-paid inheritance relation types + spouse: { + id: 'ir.application:spouse', + defaultMessage: 'Maki', + description: '', + }, + child: { + id: 'ir.application:child', + defaultMessage: 'Barn', + description: '', + }, + parent: { + id: 'ir.application:parent', + defaultMessage: 'Foreldri', + description: '', + }, + sibling: { + id: 'ir.application:sibling', + defaultMessage: 'Systkin', + description: '', + }, + other: { + id: 'ir.application:other', + defaultMessage: 'Annað', + description: '', + }, + // general yes: { id: 'ir.application:yes', @@ -1536,6 +1679,22 @@ export const m = defineMessages({ defaultMessage: 'Nei', description: '', }, + marketValue: { + id: 'ir.application:marketValuation', + defaultMessage: 'Markaðsverðmæti', + description: '', + }, + includeSpousePrePaid: { + id: 'id.application:includeSpouse', + defaultMessage: 'Ráðstafa úr sameign hjúskaps', + description: '', + }, + includeSpousePrePaidDescription: { + id: 'id.application:includeSpouseDescription', + defaultMessage: + 'Ef arfláti er í gift/ur og ráðstafa á úr sameign, þarf maki að vera með sem arfláti', + description: '', + }, // Error messages errorPropertyNumber: { id: 'ir.application:error.errorPropertyNumber', diff --git a/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts b/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts index c5b5ce8dd661..108cbb84f09c 100644 --- a/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts +++ b/libs/application/templates/inheritance-report/src/lib/utils/helpers.ts @@ -1,10 +1,16 @@ -import { getValueViaPath } from '@island.is/application/core' -import { Application, FormValue } from '@island.is/application/types' +import { NationalRegistrySpouse } from '@island.is/api/schema' +import { YES, getValueViaPath } from '@island.is/application/core' +import { + Application, + ExternalData, + FormValue, +} from '@island.is/application/types' import { InheritanceReportInfo } from '@island.is/clients/syslumenn' import { parsePhoneNumberFromString } from 'libphonenumber-js' import { MessageDescriptor } from 'react-intl' -import { ZodTypeAny } from 'zod' -import { YES } from '../constants' +import { boolean, ZodTypeAny } from 'zod' +import { Answers } from '../../types' +import { ESTATE_INHERITANCE } from '../constants' export const currencyStringToNumber = (str: string) => { if (!str) { @@ -35,6 +41,65 @@ export const getEstateDataFromApplication = ( } } +export const getSpouseFromExternalData = ( + externalData: ExternalData, +): NationalRegistrySpouse | undefined => { + const spouse = getValueViaPath(externalData, 'maritalStatus.data', {}) as + | NationalRegistrySpouse + | undefined + + return spouse +} + +export const getPrePaidOverviewSectionsToDisplay = ( + answers: FormValue, +): { + isMoney: boolean + isOther: boolean + isStocks: boolean + isRealEstate: boolean +} => { + if (answers.applicationFor === ESTATE_INHERITANCE) { + return { + isMoney: true, + isOther: true, + isStocks: true, + isRealEstate: true, + } + } + + const { money, stocks, other, realEstate } = answers.prepaidInheritance as { + money: [] + stocks: [] + other: [] + realEstate: [] + } + return { + isMoney: money.length > 0, + isOther: other.length > 0, + isStocks: stocks.length > 0, + isRealEstate: realEstate.length > 0, + } +} + +export const getPrePaidTotalValueFromApplication = ( + application: Application, +): number => { + const { answers } = application + const money = valueToNumber( + getValueViaPath(answers, 'assets.money.value', '0'), + ) + const vehicleTotal = + getValueViaPath(answers, 'assets.vehicles.total', 0) ?? 0 + const realEstateTotal = + getValueViaPath(answers, 'assets.realEstate.total', 0) ?? 0 + const otherTotal = + getValueViaPath(answers, 'assets.otherAssets.total', 0) ?? 0 + const bankAccountTotal = + getValueViaPath(answers, 'assets.bankAccounts.total', 0) ?? 0 + return money + vehicleTotal + realEstateTotal + otherTotal + bankAccountTotal +} + export const customZodError = ( zodValidation: ZodTypeAny, errorMessage: MessageDescriptor, @@ -88,6 +153,25 @@ export const isValidRealEstate = (value: string) => { return assetNumberPattern.test(value) } +export const parseLabel = ( + label: MessageDescriptor | { [key: string]: MessageDescriptor }, + answers: Answers | undefined, +): MessageDescriptor => { + if (isMessageDescriptor(label)) { + return label + } + const applicationFor: string = answers?.applicationFor as string + return label[applicationFor] +} + +export const isMessageDescriptor = (obj: any): obj is MessageDescriptor => { + return ( + obj && + typeof obj === 'object' && + ('id' in obj || 'defaultMessage' in obj || 'description' in obj) + ) +} + export const getDeceasedWasMarriedAndHadAssets = ( application: Application, ): boolean => diff --git a/libs/application/templates/inheritance-report/src/types.ts b/libs/application/templates/inheritance-report/src/types.ts index 638df5a1c4d7..0575090409fb 100644 --- a/libs/application/templates/inheritance-report/src/types.ts +++ b/libs/application/templates/inheritance-report/src/types.ts @@ -271,6 +271,7 @@ export enum RelationEnum { REPRESENTATIVE = 'representative', HEIR = 'heir', EXCHANGEMANAGER = 'exchangeManager', + GRANTOR = 'grantor', } export interface EstateMember { From 8bdf3916013f9fd960b6036f5adf9de79922ac7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9E=C3=B3r=C3=B0ur=20H?= Date: Tue, 4 Jun 2024 14:59:27 +0000 Subject: [PATCH 70/82] fix(service-portal): Filter for unread. Loading state for total page count (#15090) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../clients/documents-v2/src/lib/documentsClientV2.service.ts | 2 +- libs/service-portal/documents/src/hooks/useDocumentList.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts b/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts index 628ac5849df5..40917f084ea8 100644 --- a/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts +++ b/libs/clients/documents-v2/src/lib/documentsClientV2.service.ts @@ -29,7 +29,7 @@ export class DocumentsClientV2Service { ): T { const sanitizedObj = {} as T for (const key in obj) { - if (obj[key]) { + if (obj[key] || key === 'opened') { sanitizedObj[key] = obj[key] } } diff --git a/libs/service-portal/documents/src/hooks/useDocumentList.ts b/libs/service-portal/documents/src/hooks/useDocumentList.ts index 6dbd4cc63703..738424123eef 100644 --- a/libs/service-portal/documents/src/hooks/useDocumentList.ts +++ b/libs/service-portal/documents/src/hooks/useDocumentList.ts @@ -75,10 +75,10 @@ export const useDocumentList = () => { const totalCount = data?.documentsV2?.totalCount || 0 useEffect(() => { const pageCount = Math.ceil(totalCount / pageSize) - if (pageCount !== totalPages && pageCount !== 0) { + if (pageCount !== totalPages && !loading) { setTotalPages(pageCount) } - }, [pageSize, totalCount]) + }, [pageSize, totalCount, loading]) const filteredDocuments = data?.documentsV2?.data || [] const activeArchive = filterValue.archived === true From 7fdd969b7d7a6a79006297f75409cc787d73fce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3n=20Ingi?= <42949613+joningi98@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:06:18 +0000 Subject: [PATCH 71/82] feat:(endorsement-list): Adding pagination (#15085) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../GeneralPetitionLists.tsx | 75 ++++++++++++------- .../useGetPetitionLists.ts | 63 ++++++++++++++-- 2 files changed, 108 insertions(+), 30 deletions(-) diff --git a/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/GeneralPetitionLists.tsx b/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/GeneralPetitionLists.tsx index c64bc2c46a86..783870340d77 100644 --- a/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/GeneralPetitionLists.tsx +++ b/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/GeneralPetitionLists.tsx @@ -1,4 +1,4 @@ -import { Box, Text, Stack, ActionCard } from '@island.is/island-ui/core' +import { Box, Text, Stack, ActionCard, Button } from '@island.is/island-ui/core' import { useRouter } from 'next/router' import { useGetPetitionLists } from './useGetPetitionLists' import format from 'date-fns/format' @@ -31,7 +31,14 @@ export const GeneralPetitionLists: FC< React.PropsWithChildren > = ({ slice }) => { const router = useRouter() - const petitionLists = useGetPetitionLists() + const { + data: petitionLists, + loading: petitionLoading, + error: petitionError, + loadNextPage, + loadPreviousPage, + pageInfo: petitionPageInfo, + } = useGetPetitionLists() const t = useLocalization(slice.json) return ( @@ -50,35 +57,53 @@ export const GeneralPetitionLists: FC< }} /> - {petitionLists?.data?.length > 0 && ( + {petitionLists?.length > 0 && ( {t('title', 'Virkir listar')} )} - {petitionLists?.data?.map((petition: EndorsementList) => { - return ( - { - router.push('/undirskriftalistar/' + petition.id) - }, - }} - /> - ) - })} + {!petitionLoading && + !petitionError && + petitionLists?.map((petition: EndorsementList) => { + return ( + { + router.push('/undirskriftalistar/' + petition.id) + }, + }} + /> + ) + })} + + {petitionPageInfo?.hasPreviousPage ? ( + + + + ) : undefined} + {petitionPageInfo?.hasNextPage ? ( + + + + ) : undefined} + ) } diff --git a/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/useGetPetitionLists.ts b/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/useGetPetitionLists.ts index 0ac4afba5128..6e476f71c4ae 100644 --- a/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/useGetPetitionLists.ts +++ b/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/useGetPetitionLists.ts @@ -1,5 +1,6 @@ import gql from 'graphql-tag' import { useQuery } from '@apollo/client' +import { useState } from 'react' interface PetitionListResponse { endorsementSystemGetGeneralPetitionLists: any @@ -54,21 +55,73 @@ const GetGeneralPetitionListEndorsements = gql` ` export const useGetPetitionLists = () => { - const { data: endorsementListsResponse } = useQuery( + const [pagination, setPagination] = useState({ after: '', before: '' }) + const { data, loading, error, fetchMore } = useQuery( GetGeneralPetitionLists, { variables: { input: { tags: 'generalPetition', - limit: 1000, + after: pagination.after, + before: pagination.before, + limit: 10, }, }, }, ) - return ( - endorsementListsResponse?.endorsementSystemGetGeneralPetitionLists ?? [] - ) + const loadNextPage = () => { + if (data?.endorsementSystemGetGeneralPetitionLists.pageInfo.hasNextPage) { + setPagination({ + ...pagination, + after: data.endorsementSystemGetGeneralPetitionLists.pageInfo.endCursor, + before: '', + }) + fetchMore({ + variables: { + input: { + tags: 'generalPetition', + limit: 10, + after: + data.endorsementSystemGetGeneralPetitionLists.pageInfo.endCursor, + }, + }, + }) + } + } + + const loadPreviousPage = () => { + if ( + data?.endorsementSystemGetGeneralPetitionLists.pageInfo.hasPreviousPage + ) { + setPagination({ + ...pagination, + after: '', + before: + data.endorsementSystemGetGeneralPetitionLists.pageInfo.startCursor, + }) + fetchMore({ + variables: { + input: { + tags: 'generalPetition', + limit: 10, + before: + data.endorsementSystemGetGeneralPetitionLists.pageInfo + .startCursor, + }, + }, + }) + } + } + + return { + data: data?.endorsementSystemGetGeneralPetitionLists?.data ?? [], + loading, + error, + loadNextPage, + loadPreviousPage, + pageInfo: data?.endorsementSystemGetGeneralPetitionLists.pageInfo, + } } export const useGetPetitionListEndorsements = (listId: string) => { From d380505338282483639a4f0ff2e3cbc786d19677 Mon Sep 17 00:00:00 2001 From: albinagu <47886428+albinagu@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:15:27 +0000 Subject: [PATCH 72/82] fix(inheritance-report): Total calculations (#15073) * fix(inheritance-report): Total calculations * code rabbit review fix * heirspercentage additional heir --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/fields/OtherAssetsRepeater/index.tsx | 2 +- .../src/fields/TextFieldsRepeater/index.tsx | 2 +- .../src/components/ShareInput/index.tsx | 2 +- .../src/fields/AssetsRepeater/index.tsx | 2 +- .../src/fields/BusinessAssetsRepeater/index.tsx | 3 +-- .../src/fields/CalculateShare/index.tsx | 6 +----- .../HeirsAndPartitionRepeater/AdditionalHeir.tsx | 11 +---------- .../fields/HeirsAndPartitionRepeater/index.tsx | 2 ++ .../src/fields/OtherAssetsRepeater/index.tsx | 2 +- .../src/fields/ReportFieldsRepeater/index.tsx | 2 +- .../inheritance-report/src/lib/dataSchema.ts | 16 ++++++++++------ 11 files changed, 21 insertions(+), 29 deletions(-) diff --git a/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx b/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx index 3b6eb54731da..ed295e063513 100644 --- a/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx +++ b/libs/application/templates/estate/src/fields/OtherAssetsRepeater/index.tsx @@ -54,7 +54,7 @@ export const OtherAssetsRepeater: FC< useEffect(() => { calculateTotal() - }, [calculateTotal]) + }, [fields, calculateTotal]) const handleAddRepeaterFields = () => { const values = props.fields.map((field: object) => { diff --git a/libs/application/templates/estate/src/fields/TextFieldsRepeater/index.tsx b/libs/application/templates/estate/src/fields/TextFieldsRepeater/index.tsx index 37c8994e07d3..da500ed93491 100644 --- a/libs/application/templates/estate/src/fields/TextFieldsRepeater/index.tsx +++ b/libs/application/templates/estate/src/fields/TextFieldsRepeater/index.tsx @@ -75,7 +75,7 @@ export const TextFieldsRepeater: FC< useEffect(() => { calculateTotal() - }, [calculateTotal]) + }, [fields, calculateTotal]) const handleAddRepeaterFields = useCallback(() => { const values = props.fields.map((field: Field) => { diff --git a/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx b/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx index ec401e70e580..87f3d03dcc5f 100644 --- a/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx +++ b/libs/application/templates/inheritance-report/src/components/ShareInput/index.tsx @@ -158,7 +158,7 @@ export const ShareInput = ({ return onAfterChange?.(numberValue) } }} - hasError={hasError ?? false} + hasError={(!disabled && hasError) ?? false} errorMessage={formatMessage(m.invalidShareValue)} disabled={disabled} required={required} diff --git a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx index cf1174dbb888..7cbe11193827 100644 --- a/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/AssetsRepeater/index.tsx @@ -101,7 +101,7 @@ export const AssetsRepeater: FC< useEffect(() => { calculateTotal() - }, [fields]) + }, [fields, calculateTotal]) const handleAddRepeaterFields = () => { const values = props.fields.map((field: object) => { diff --git a/libs/application/templates/inheritance-report/src/fields/BusinessAssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/BusinessAssetsRepeater/index.tsx index 0723c6ca2c3b..c11f6cbe0084 100644 --- a/libs/application/templates/inheritance-report/src/fields/BusinessAssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/BusinessAssetsRepeater/index.tsx @@ -93,8 +93,7 @@ export const BusinessAssetsRepeater: FC< useEffect(() => { calculateTotal() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [fields, calculateTotal]) useEffect(() => { const estData = diff --git a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx index b5152fc0f736..b2d8da4456eb 100644 --- a/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/CalculateShare/index.tsx @@ -41,7 +41,6 @@ export const CalculateShare: FC> = ({ const { answers } = application const [, updateState] = useState() const forceUpdate = useCallback(() => updateState({}), []) - const { formatMessage } = useLocale() const { setValue, getValues } = useFormContext() const [total, setTotal] = useState(0) const [debtsTotal, setDebtsTotal] = useState(0) @@ -344,10 +343,7 @@ export const CalculateShare: FC> = ({ // Set the total value of debts + funeral costs useEffect(() => { - const funeralCost = getNumberValue('funeralCost.total') - const debtsTotalValue = getNumberValue('debts.debtsTotal') + funeralCost - - setDebtsTotal(debtsTotalValue) + setDebtsTotal(getNumberValue('debts.debtsTotal')) }, [getNumberValue, total]) // Set the total value of all deceased seperate assets diff --git a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx index b65df5ea7048..735a4524bdd3 100644 --- a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx +++ b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/AdditionalHeir.tsx @@ -279,16 +279,7 @@ export const AdditionalHeir = ({ onAfterChange={(val) => { updateValues(fieldIndex, val, customFieldIndex) }} - errorMessage={ - error && error[index] - ? error[index][customField.id] - : undefined - } - hasError={ - error && error[index] - ? !!error[index][customField.id] - : false - } + hasError={!!error?.heirsPercentage} required /> diff --git a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/index.tsx index dbb2b35a5541..75852b2cafdc 100644 --- a/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/HeirsAndPartitionRepeater/index.tsx @@ -365,6 +365,7 @@ export const HeirsAndPartitionRepeater: FC< clearErrors(`${fieldIndex}.email`) clearErrors(`${fieldIndex}.advocate.phone`) clearErrors(`${fieldIndex}.advocate.email`) + clearErrors(`${fieldIndex}.heirsPercentage`) calculateTotal() }} > @@ -594,6 +595,7 @@ export const HeirsAndPartitionRepeater: FC< [] as JSX.Element[], )} {fields.map((member: GenericFormField, index) => { + console.log(error, 'errrrrr') if (member.initial) return null return ( diff --git a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx index 38a264c6b066..a6d93623881b 100644 --- a/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/OtherAssetsRepeater/index.tsx @@ -73,7 +73,7 @@ export const OtherAssetsRepeater: FC< useEffect(() => { calculateTotal() - }, [calculateTotal]) + }, [fields, calculateTotal]) const handleAddRepeaterFields = () => { const values = props.fields.map((field: object) => { diff --git a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx index 3dab5193bb15..87a55a7b2b03 100644 --- a/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx +++ b/libs/application/templates/inheritance-report/src/fields/ReportFieldsRepeater/index.tsx @@ -122,7 +122,7 @@ export const ReportFieldsRepeater: FC< useEffect(() => { calculateTotal() - }, [calculateTotal]) + }, [fields, calculateTotal]) //TODO: connect to API const debtTypes = [] as any diff --git a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts index 0d8000c201ac..885c4487f192 100644 --- a/libs/application/templates/inheritance-report/src/lib/dataSchema.ts +++ b/libs/application/templates/inheritance-report/src/lib/dataSchema.ts @@ -473,12 +473,7 @@ export const inheritanceReportSchema = z.object({ enabled: z.boolean(), phone: z.string().optional(), email: z.string(), - heirsPercentage: z.string().refine((v) => { - if (!v) return true - - const num = parseInt(v, 10) ?? 0 - return num > 0 && num < 101 - }), + heirsPercentage: z.string().optional(), taxFreeInheritance: z.string(), inheritance: z.string(), taxableInheritance: z.string(), @@ -493,6 +488,15 @@ export const inheritanceReportSchema = z.object({ }) .optional(), }) + .refine( + ({ enabled, heirsPercentage }) => { + const num = heirsPercentage ? parseInt(heirsPercentage, 10) : 0 + return enabled ? num > 0 && num < 101 : true + }, + { + path: ['heirsPercentage'], + }, + ) .refine( ({ enabled, foreignCitizenship, dateOfBirth }) => { if (!enabled) return true From d3ce693473178a3403c6cab58008979d9427bdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 4 Jun 2024 17:47:13 +0000 Subject: [PATCH 73/82] fix(j-s): Completed Case States in Defender Case Lists (#15059) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../backend/src/app/modules/case/limitedAccessCase.service.ts | 1 + .../web/src/components/FormProvider/limitedAccessCase.graphql | 1 + .../web/src/routes/Defender/Cases/defenderCases.graphql | 1 + .../web/src/routes/Shared/Cases/prisonCases.graphql | 1 + 4 files changed, 4 insertions(+) diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index 10ddc4008743..6aeeaae0d7eb 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -97,6 +97,7 @@ export const attributes: (keyof Case)[] = [ 'appealRulingModifiedHistory', 'requestAppealRulingNotToBePublished', 'prosecutorsOfficeId', + 'indictmentRulingDecision', 'indictmentHash', ] diff --git a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql index e54f9fba060c..9e1c4e30fb2e 100644 --- a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql @@ -144,5 +144,6 @@ query LimitedAccessCase($input: CaseQueryInput!) { name } postponedIndefinitelyExplanation + indictmentRulingDecision } } diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql index 230b576c0c32..36e8a9e69091 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql +++ b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql @@ -27,5 +27,6 @@ query DefenderCases($input: CaseListQueryInput) { initialRulingDate rulingDate postponedIndefinitelyExplanation + indictmentRulingDecision } } diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql index 7466a685cf10..e3235615b3d3 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql @@ -81,5 +81,6 @@ query PrisonCases { active } postponedIndefinitelyExplanation + indictmentRulingDecision } } From 1566034ba05f8783bf1aa7250b2416c86809f7d3 Mon Sep 17 00:00:00 2001 From: unakb Date: Tue, 4 Jun 2024 18:19:05 +0000 Subject: [PATCH 74/82] feat(j-s): API endpoint to update subpoena (#15051) * fix(j-s): Digital mailbox api config * fix(j-s): Config * fix(j-s): Added missing config value * Update judicial-system-xrd-robot-api.ts * Update app.config.ts * Update yaml * chore(j-s): Lawyers lib and controller added to digital mailbox api * Moving some files around * fix(j-s): cleanup * chore(j-s): Cleanup * import types as types * Update lawyers.service.ts * Update defender.controller.ts * chore(j-s): New functionality for subpoenas in API * Update case.controller.ts * chore(j-s): Continued API work * Update 20240530132001-update-defendant.js * chore(j-s): Retrieve ssn from ids token * fix(j-s): national id handling for defender * chore: nx format:write update dirty files * Update case.controller.ts * Update internalDefendant.controller.ts * fix(j-s): Test * Update SelectDefender.tsx * fix(j-s): Guards test * Update 20240514111505-update-defendant.js * Update internalDefendant.controller.ts * fix(j-s): cleanup * fix(j-s): Validation * Update subpoena.response.ts * fix(j-s): Controller decorators * Update internalDefendant.controller.ts * chore(j-s): Cleanups and handling different national id formats * fix(j-s): Feedback fixes * Update case.controller.ts --------- Co-authored-by: andes-it Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../defendant/dto/updateDefendant.input.ts | 11 +- .../defendant/models/defendant.model.ts | 8 +- .../20240530132001-update-defendant.js | 56 +++ .../modules/case/internalCase.controller.ts | 11 +- .../app/modules/case/internalCase.service.ts | 21 +- .../modules/defendant/defendant.service.ts | 33 ++ .../defendant/dto/createDefendant.dto.ts | 8 +- .../defendant/dto/updateDefendant.dto.ts | 7 +- .../defendant/internalDefendant.controller.ts | 39 ++- .../defendant/models/defendant.model.ts | 11 +- .../internalDefendantControllerGuards.spec.ts | 20 +- .../src/app/modules/cases/case.controller.ts | 58 +++- .../src/app/modules/cases/case.service.ts | 318 +++++++++--------- .../src/app/modules/cases/dto/subpoena.dto.ts | 17 + .../app/modules/cases/models/case.response.ts | 88 +++++ .../modules/cases/models/cases.response.ts | 33 ++ .../models/internal/internalCase.response.ts | 29 ++ .../models/internal/internalCases.response.ts | 8 + .../internal/internalDefendant.response.ts | 7 + .../cases/models/internalCase.response.ts | 23 -- .../cases/models/internalCases.response.ts | 17 - .../modules/cases/models/subpoena.response.ts | 50 +++ .../src/components/FormProvider/case.graphql | 2 +- .../FormProvider/limitedAccessCase.graphql | 2 +- .../Indictments/Defender/SelectDefender.tsx | 14 +- .../CourtOfAppeal/Cases/appealdCases.graphql | 2 +- .../Defender/Cases/defenderCases.graphql | 2 +- .../web/src/routes/Shared/Cases/cases.graphql | 2 +- .../routes/Shared/Cases/prisonCases.graphql | 2 +- .../useCase/limitedAccessUpdateCase.graphql | 2 +- .../utils/hooks/useCase/updateCase.graphql | 2 +- apps/judicial-system/web/src/utils/mocks.ts | 2 +- .../judicial-system/web/src/utils/validate.ts | 3 +- .../audit-trail/src/lib/auditTrail.service.ts | 2 + libs/judicial-system/types/src/index.ts | 3 +- .../types/src/lib/defendant.ts | 21 +- 36 files changed, 651 insertions(+), 283 deletions(-) create mode 100644 apps/judicial-system/backend/migrations/20240530132001-update-defendant.js create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/dto/subpoena.dto.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCase.response.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCases.response.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalDefendant.response.ts delete mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts delete mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts create mode 100644 apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/subpoena.response.ts diff --git a/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts b/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts index 8b179cee53a5..a77d184629b5 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts @@ -4,6 +4,7 @@ import { Field, ID, InputType } from '@nestjs/graphql' import { DefendantPlea, + DefenderChoice, Gender, ServiceRequirement, } from '@island.is/judicial-system/types' @@ -68,11 +69,6 @@ export class UpdateDefendantInput { @Field(() => String, { nullable: true }) readonly defenderPhoneNumber?: string - @Allow() - @IsOptional() - @Field(() => Boolean, { nullable: true }) - readonly defendantWaivesRightToCounsel?: boolean - @Allow() @IsOptional() @Field(() => DefendantPlea, { nullable: true }) @@ -87,4 +83,9 @@ export class UpdateDefendantInput { @IsOptional() @Field(() => String, { nullable: true }) readonly verdictViewDate?: string + + @Allow() + @IsOptional() + @Field(() => DefenderChoice, { nullable: true }) + readonly defenderChoice?: DefenderChoice } diff --git a/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts b/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts index 50c1fed8da12..c52460c4125a 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts @@ -2,6 +2,7 @@ import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql' import { DefendantPlea, + DefenderChoice, Gender, ServiceRequirement, } from '@island.is/judicial-system/types' @@ -9,6 +10,7 @@ import { registerEnumType(Gender, { name: 'Gender' }) registerEnumType(DefendantPlea, { name: 'DefendantPlea' }) registerEnumType(ServiceRequirement, { name: 'ServiceRequirement' }) +registerEnumType(DefenderChoice, { name: 'DefenderChoice' }) @ObjectType() export class Defendant { @@ -54,9 +56,6 @@ export class Defendant { @Field(() => String, { nullable: true }) readonly defenderPhoneNumber?: string - @Field(() => Boolean, { nullable: true }) - readonly defendantWaivesRightToCounsel?: boolean - @Field(() => DefendantPlea, { nullable: true }) readonly defendantPlea?: DefendantPlea @@ -68,4 +67,7 @@ export class Defendant { @Field(() => String, { nullable: true }) readonly verdictAppealDeadline?: string + + @Field(() => DefenderChoice, { nullable: true }) + readonly defenderChoice?: DefenderChoice } diff --git a/apps/judicial-system/backend/migrations/20240530132001-update-defendant.js b/apps/judicial-system/backend/migrations/20240530132001-update-defendant.js new file mode 100644 index 000000000000..2e08613fd81e --- /dev/null +++ b/apps/judicial-system/backend/migrations/20240530132001-update-defendant.js @@ -0,0 +1,56 @@ +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => + queryInterface + .addColumn( + 'defendant', + 'defender_choice', + { + type: Sequelize.STRING, + allowNull: true, + }, + { transaction: t }, + ) + .then(() => + queryInterface.sequelize.query( + `UPDATE "defendant" SET defender_choice = 'WAIVE' WHERE defendant_waives_right_to_counsel = true;`, + { transaction: t }, + ), + ) + .then(() => + queryInterface.removeColumn( + 'defendant', + 'defendant_waives_right_to_counsel', + { transaction: t }, + ), + ), + ) + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => + queryInterface + .addColumn( + 'defendant', + 'defendant_waives_right_to_counsel', + { + type: Sequelize.BOOLEAN, + defaultValue: false, + allowNull: false, + }, + { transaction: t }, + ) + .then(() => + queryInterface.sequelize.query( + `UPDATE "defendant" SET defendant_waives_right_to_counsel = true WHERE defender_choice = 'WAIVE';`, + { transaction: t }, + ), + ) + .then(() => + queryInterface.removeColumn('defendant', 'defender_choice', { + transaction: t, + }), + ), + ) + }, +} diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts index 7df5b1887435..bc47e8277231 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts @@ -80,9 +80,10 @@ export class InternalCaseController { @Body() internalCasesDto: InternalCasesDto, ): Promise { this.logger.debug('Getting all indictment cases') - const nationalId = formatNationalId(internalCasesDto.nationalId) - return this.internalCaseService.getIndictmentCases(nationalId) + return this.internalCaseService.getIndictmentCases( + internalCasesDto.nationalId, + ) } @Post('cases/indictment/:caseId') @@ -95,9 +96,11 @@ export class InternalCaseController { @Body() internalCasesDto: InternalCasesDto, ): Promise { this.logger.debug(`Getting indictment case ${caseId}`) - const nationalId = formatNationalId(internalCasesDto.nationalId) - return this.internalCaseService.getIndictmentCase(caseId, nationalId) + return this.internalCaseService.getIndictmentCase( + caseId, + internalCasesDto.nationalId, + ) } @UseGuards(CaseExistsGuard) diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index 91f73348df61..028c0a158b3f 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -18,7 +18,10 @@ import { FormatMessage, IntlService } from '@island.is/cms-translations' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' import type { ConfigType } from '@island.is/nest/config' -import { formatCaseType } from '@island.is/judicial-system/formatters' +import { + formatCaseType, + formatNationalId, +} from '@island.is/judicial-system/formatters' import { CaseFileCategory, CaseOrigin, @@ -1048,6 +1051,8 @@ export class InternalCaseService { } async getIndictmentCases(nationalId: string): Promise { + const formattedNationalId = formatNationalId(nationalId) + return this.caseModel.findAll({ include: [ { model: Defendant, as: 'defendants' }, @@ -1057,7 +1062,10 @@ export class InternalCaseService { attributes: ['id', 'courtCaseNumber', 'type', 'state'], where: { type: CaseType.INDICTMENT, - '$defendants.national_id$': nationalId, + [Op.or]: [ + { '$defendants.national_id$': nationalId }, + { '$defendants.national_id$': formattedNationalId }, + ], }, }) } @@ -1066,6 +1074,10 @@ export class InternalCaseService { caseId: string, nationalId: string, ): Promise { + // The national id could be without a hyphen or with a hyphen so we need to + // search for both + const formattedNationalId = formatNationalId(nationalId) + const caseById = await this.caseModel.findOne({ include: [ { model: Defendant, as: 'defendants' }, @@ -1078,7 +1090,10 @@ export class InternalCaseService { where: { type: CaseType.INDICTMENT, id: caseId, - '$defendants.national_id$': nationalId, + [Op.or]: [ + { '$defendants.national_id$': nationalId }, + { '$defendants.national_id$': formattedNationalId }, + ], }, }) diff --git a/apps/judicial-system/backend/src/app/modules/defendant/defendant.service.ts b/apps/judicial-system/backend/src/app/modules/defendant/defendant.service.ts index 30fdd92b23af..22e881540a50 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/defendant.service.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/defendant.service.ts @@ -5,12 +5,14 @@ import { Inject, Injectable, InternalServerErrorException, + NotFoundException, } from '@nestjs/common' import { InjectModel } from '@nestjs/sequelize' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' +import { formatNationalId } from '@island.is/judicial-system/formatters' import { CaseMessage, MessageService, @@ -195,6 +197,37 @@ export class DefendantService { return updatedDefendant } + async updateByNationalId( + caseId: string, + defendantNationalId: string, + update: UpdateDefendantDto, + ): Promise { + const formattedNationalId = formatNationalId(defendantNationalId) + + const [numberOfAffectedRows, defendants] = await this.defendantModel.update( + update, + { + where: { + caseId, + [Op.or]: [ + { national_id: formattedNationalId }, + { national_id: defendantNationalId }, + ], + }, + returning: true, + }, + ) + + const updatedDefendant = this.getUpdatedDefendant( + numberOfAffectedRows, + defendants, + defendants[0].id, + caseId, + ) + + return updatedDefendant + } + async delete( theCase: Case, defendantId: string, diff --git a/apps/judicial-system/backend/src/app/modules/defendant/dto/createDefendant.dto.ts b/apps/judicial-system/backend/src/app/modules/defendant/dto/createDefendant.dto.ts index 31e4109c16d8..eee5ea58da99 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/dto/createDefendant.dto.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/dto/createDefendant.dto.ts @@ -2,7 +2,7 @@ import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator' import { ApiPropertyOptional } from '@nestjs/swagger' -import { Gender } from '@island.is/judicial-system/types' +import { DefenderChoice, Gender } from '@island.is/judicial-system/types' export class CreateDefendantDto { @IsOptional() @@ -56,7 +56,7 @@ export class CreateDefendantDto { readonly defenderPhoneNumber?: string @IsOptional() - @IsBoolean() - @ApiPropertyOptional({ type: Boolean }) - readonly defendantWaivesRightToCounsel?: boolean + @IsEnum(DefenderChoice) + @ApiPropertyOptional({ enum: DefenderChoice }) + readonly defenderChoice?: DefenderChoice } diff --git a/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts b/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts index 922535aab96e..e9887e658203 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts @@ -4,6 +4,7 @@ import { ApiPropertyOptional } from '@nestjs/swagger' import { DefendantPlea, + DefenderChoice, Gender, ServiceRequirement, } from '@island.is/judicial-system/types' @@ -60,9 +61,9 @@ export class UpdateDefendantDto { readonly defenderPhoneNumber?: string @IsOptional() - @IsBoolean() - @ApiPropertyOptional({ type: Boolean }) - readonly defendantWaivesRightToCounsel?: boolean + @IsEnum(DefenderChoice) + @ApiPropertyOptional({ enum: DefenderChoice }) + readonly defenderChoice?: DefenderChoice @IsOptional() @IsEnum(DefendantPlea) diff --git a/apps/judicial-system/backend/src/app/modules/defendant/internalDefendant.controller.ts b/apps/judicial-system/backend/src/app/modules/defendant/internalDefendant.controller.ts index e4736064af61..1fbefa6b9af2 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/internalDefendant.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/internalDefendant.controller.ts @@ -3,10 +3,11 @@ import { Controller, Inject, Param, + Patch, Post, UseGuards, } from '@nestjs/common' -import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger' +import { ApiCreatedResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' @@ -19,26 +20,26 @@ import { import { Case, CaseExistsGuard, CurrentCase } from '../case' import { DeliverDefendantToCourtDto } from './dto/deliverDefendantToCourt.dto' +import { UpdateDefendantDto } from './dto/updateDefendant.dto' import { CurrentDefendant } from './guards/defendant.decorator' import { DefendantExistsGuard } from './guards/defendantExists.guard' import { Defendant } from './models/defendant.model' import { DeliverResponse } from './models/deliver.response' import { DefendantService } from './defendant.service' -@Controller( - `api/internal/case/:caseId/${ - messageEndpoint[MessageType.DELIVERY_TO_COURT_DEFENDANT] - }/:defendantId`, -) +@Controller('api/internal/case/:caseId') @ApiTags('internal defendants') -@UseGuards(TokenGuard, CaseExistsGuard, DefendantExistsGuard) +@UseGuards(TokenGuard, CaseExistsGuard) export class InternalDefendantController { constructor( private readonly defendantService: DefendantService, @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} - @Post() + @UseGuards(DefendantExistsGuard) + @Post( + `${messageEndpoint[MessageType.DELIVERY_TO_COURT_DEFENDANT]}/:defendantId`, + ) @ApiCreatedResponse({ type: DeliverResponse, description: 'Delivers a case file to court', @@ -60,4 +61,26 @@ export class InternalDefendantController { deliverDefendantToCourtDto.user, ) } + + @Patch('defense/:defendantNationalId') + @ApiOkResponse({ + type: Defendant, + description: 'Assigns defense choice to defendant', + }) + async assignDefender( + @Param('caseId') caseId: string, + @Param('defendantNationalId') defendantNationalId: string, + @CurrentCase() theCase: Case, + @Body() updatedDefendantChoice: UpdateDefendantDto, + ): Promise { + this.logger.debug(`Assigning defense choice to defendant in case ${caseId}`) + + const updatedDefendant = await this.defendantService.updateByNationalId( + theCase.id, + defendantNationalId, + updatedDefendantChoice, + ) + + return updatedDefendant + } } diff --git a/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts b/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts index 053d19ff4bf2..1d6b1e0f471e 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts @@ -13,6 +13,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' import { DefendantPlea, + DefenderChoice, Gender, ServiceRequirement, } from '@island.is/judicial-system/types' @@ -94,9 +95,13 @@ export class Defendant extends Model { @ApiPropertyOptional({ type: String }) defenderPhoneNumber?: string - @Column({ type: DataType.BOOLEAN, allowNull: false, defaultValue: false }) - @ApiProperty({ type: Boolean }) - defendantWaivesRightToCounsel!: boolean + @Column({ + type: DataType.ENUM, + allowNull: true, + values: Object.values(DefenderChoice), + }) + @ApiPropertyOptional({ enum: DefenderChoice }) + defenderChoice?: DefenderChoice @Column({ type: DataType.ENUM, diff --git a/apps/judicial-system/backend/src/app/modules/defendant/test/internalDefendantController/internalDefendantControllerGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/defendant/test/internalDefendantController/internalDefendantControllerGuards.spec.ts index 6e88a771a9f5..ae0ad03605fb 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/test/internalDefendantController/internalDefendantControllerGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/test/internalDefendantController/internalDefendantControllerGuards.spec.ts @@ -14,8 +14,8 @@ describe('InternalDefendantController - guards', () => { guards = Reflect.getMetadata('__guards__', InternalDefendantController) }) - it('should have three guards', () => { - expect(guards).toHaveLength(3) + it('should have two guards', () => { + expect(guards).toHaveLength(2) }) describe('TokenGuard', () => { @@ -42,14 +42,14 @@ describe('InternalDefendantController - guards', () => { }) }) - describe('DefendantExistsGuard', () => { - let guard: CanActivate - - beforeEach(() => { - guard = new guards[2]() - }) - - it('should have DefendantExistsGuard as guard 3', () => { + describe('Method level guards', () => { + it('should have DefendantExistsGuard on deliverDefendantToCourt method', () => { + const methodGuards = Reflect.getMetadata( + '__guards__', + InternalDefendantController.prototype.deliverDefendantToCourt, + ) + expect(methodGuards).toHaveLength(1) + const guard = new methodGuards[0]() expect(guard).toBeInstanceOf(DefendantExistsGuard) }) }) diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts index 3f6a516708d4..59167a87832b 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.controller.ts @@ -1,19 +1,23 @@ import { + Body, Controller, Get, Inject, Param, + Patch, Query, UseGuards, } from '@nestjs/common' -import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger' +import { ApiOkResponse, ApiTags } from '@nestjs/swagger' import type { User } from '@island.is/auth-nest-tools' import { CurrentUser, IdsUserGuard } from '@island.is/auth-nest-tools' import { type Logger, LOGGER_PROVIDER } from '@island.is/logging' +import { UpdateSubpoenaDto } from './dto/subpoena.dto' import { CaseResponse } from './models/case.response' import { CasesResponse } from './models/cases.response' +import { SubpoenaResponse } from './models/subpoena.response' import { CaseService } from './case.service' @Controller('api') @@ -22,23 +26,12 @@ import { CaseService } from './case.service' export class CaseController { constructor( private readonly caseService: CaseService, + @Inject(LOGGER_PROVIDER) private readonly logger: Logger, ) {} - @Get('test') - @ApiCreatedResponse({ type: String, description: 'Test connection' }) - async test(@CurrentUser() user: User): Promise { - this.logger.debug('Testing connection') - - return this.caseService.testConnection(user.nationalId) - } - @Get('cases') - @ApiCreatedResponse({ - type: CasesResponse, - isArray: true, - description: 'Get all cases', - }) + @ApiOkResponse({ type: String, description: 'Get all cases' }) async getAllCases( @CurrentUser() user: User, @Query() query?: { lang: string }, @@ -49,7 +42,7 @@ export class CaseController { } @Get('case/:caseId') - @ApiCreatedResponse({ type: CaseResponse, description: 'Get case by id' }) + @ApiOkResponse({ type: CaseResponse, description: 'Get case by id' }) async getCase( @Param('caseId') caseId: string, @CurrentUser() user: User, @@ -57,6 +50,39 @@ export class CaseController { ): Promise { this.logger.debug('Getting case by id') - return this.caseService.getCaseById(caseId, user.nationalId, query?.lang) + return this.caseService.getCase(caseId, user.nationalId, query?.lang) + } + + @Get('case/:caseId/subpoena') + @ApiOkResponse({ + type: () => SubpoenaResponse, + description: 'Get subpoena by case id', + }) + async getSubpoena( + @Param('caseId') caseId: string, + @CurrentUser() user: User, + ): Promise { + this.logger.debug(`Getting subpoena by case id ${caseId}`) + + return this.caseService.getSubpoena(caseId, user.nationalId) + } + + @Patch('case/:caseId/subpoena') + @ApiOkResponse({ + type: () => SubpoenaResponse, + description: 'Update subpoena info', + }) + async updateSubpoena( + @CurrentUser() user: User, + @Param('caseId') caseId: string, + @Body() defenderAssignment: UpdateSubpoenaDto, + ): Promise { + this.logger.debug(`Assigning defender to subpoena ${caseId}`) + + return this.caseService.updateSubpoena( + user.nationalId, + caseId, + defenderAssignment, + ) } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts index 7da411be3eb3..76b4083fe6fc 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts @@ -11,12 +11,16 @@ import { AuditedAction, AuditTrailService, } from '@island.is/judicial-system/audit-trail' -import { isCompletedCase } from '@island.is/judicial-system/types' +import { LawyersService } from '@island.is/judicial-system/lawyers' +import { DefenderChoice } from '@island.is/judicial-system/types' +import { UpdateSubpoenaDto } from './dto/subpoena.dto' import { CaseResponse } from './models/case.response' import { CasesResponse } from './models/cases.response' -import { InternalCaseResponse } from './models/internalCase.response' -import { InternalCasesResponse } from './models/internalCases.response' +import { InternalCaseResponse } from './models/internal/internalCase.response' +import { InternalCasesResponse } from './models/internal/internalCases.response' +import { InternalDefendantResponse } from './models/internal/internalDefendant.response' +import { SubpoenaResponse } from './models/subpoena.response' import { caseModuleConfig } from './case.config' @Injectable() @@ -25,132 +29,130 @@ export class CaseService { @Inject(caseModuleConfig.KEY) private readonly config: ConfigType, private readonly auditTrailService: AuditTrailService, + private readonly lawyersService: LawyersService, ) {} - private format( - response: InternalCasesResponse[], - lang?: string, - ): CasesResponse[] { - return response.map((item: InternalCasesResponse) => { - const language = lang?.toLowerCase() - - return { - id: item.id, - state: { - color: isCompletedCase(item.state) ? 'purple' : 'blue', - label: - language === 'en' - ? isCompletedCase(item.state) - ? 'Completed' - : 'Active' - : isCompletedCase(item.state) - ? 'Lokið' - : 'Í vinnslu', - }, - caseNumber: - language === 'en' - ? `Case number ${item.courtCaseNumber}` - : `Málsnúmer ${item.courtCaseNumber}`, - type: language === 'en' ? 'Indictment' : 'Ákæra', - } - }) + async getCases(nationalId: string, lang?: string): Promise { + return this.auditTrailService.audit( + 'digital-mailbox-api', + AuditedAction.GET_INDICTMENTS, + this.getCasesInfo(nationalId, lang), + nationalId, + ) } - private formatCase(res: InternalCaseResponse, lang?: string): CaseResponse { - const language = lang?.toLowerCase() - const defendant = res.defendants[0] - - return { - data: { - caseNumber: - language === 'en' - ? `Case number ${res.courtCaseNumber}` - : `Málsnúmer ${res.courtCaseNumber}`, - groups: [ - { - label: language === 'en' ? 'Defendant' : 'Varnaraðili', - items: [ - [language === 'en' ? 'Name' : 'Nafn', defendant.name], - [ - language === 'en' ? 'National ID' : 'Kennitala', - defendant.nationalId, - ], - [ - language === 'en' ? 'Address' : 'Heimilisfang', - defendant.address, - ], - ].map((item) => ({ - label: item[0] ?? '', - value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), - })), - }, - { - label: language === 'en' ? 'Defender' : 'Verjandi', - items: [ - [language === 'en' ? 'Name' : 'Nafn', defendant.defenderName], - [ - language === 'en' ? 'Email' : 'Netfang', - defendant.defenderEmail, - 'email', - ], - [ - language === 'en' ? 'Phone Nr.' : 'Símanúmer', - defendant.defenderPhoneNumber, - 'tel', - ], - ].map((item) => ({ - label: item[0] ?? '', - value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), - linkType: item[2] ?? undefined, - })), - }, - { - label: language === 'en' ? 'Information' : 'Málsupplýsingar', - items: [ - { - label: language === 'en' ? 'Type' : 'Tegund', - value: language === 'en' ? 'Indictment' : 'Ákæra', - }, - { - label: - language === 'en' ? 'Case number' : 'Málsnúmer héraðsdóms', - value: res.courtCaseNumber, - }, - { - label: language === 'en' ? 'Court' : 'Dómstóll', - value: res.court.name, - }, - { - label: language === 'en' ? 'Judge' : 'Dómari', - value: res.judge.name, - }, - { - label: language === 'en' ? 'Institution' : 'Embætti', - value: res.prosecutorsOffice.name, - }, - { - label: language === 'en' ? 'Prosecutor' : 'Ákærandi', - value: res.prosecutor.name, - }, - ], - }, - ], - }, - } + async getCase( + id: string, + nationalId: string, + lang?: string, + ): Promise { + return this.auditTrailService.audit( + 'digital-mailbox-api', + AuditedAction.GET_INDICTMENT, + this.getCaseInfo(id, nationalId, lang), + () => id, + ) } - private async test(nationalId: string): Promise { - return `OK ${nationalId}` + async getSubpoena( + caseId: string, + nationalId: string, + ): Promise { + return this.auditTrailService.audit( + 'digital-mailbox-api', + AuditedAction.GET_SUBPOENA, + this.getSubpoenaInfo(caseId, nationalId), + nationalId, + ) } - async testConnection(nationalId: string): Promise { - return this.test(nationalId) + async updateSubpoena( + nationalId: string, + caseId: string, + updateSubpoena: UpdateSubpoenaDto, + ): Promise { + return await this.auditTrailService.audit( + 'digital-mailbox-api', + AuditedAction.ASSIGN_DEFENDER_TO_SUBPOENA, + this.updateSubpoenaDefender(nationalId, caseId, updateSubpoena), + nationalId, + ) } - private async getAllCases( + private async getCasesInfo( nationalId: string, lang?: string, ): Promise { + const response = await this.fetchCases(nationalId) + return CasesResponse.fromInternalCasesResponse(response, lang) + } + + private async getCaseInfo( + id: string, + nationalId: string, + lang?: string, + ): Promise { + const response = await this.fetchCase(id, nationalId) + return CaseResponse.fromInternalCaseResponse(response, lang) + } + + private async getSubpoenaInfo( + caseId: string, + defendantNationalId: string, + ): Promise { + const caseData = await this.fetchCase(caseId, defendantNationalId) + return SubpoenaResponse.fromInternalCaseResponse( + caseData, + defendantNationalId, + ) + } + + private async updateSubpoenaDefender( + defendantNationalId: string, + caseId: string, + defenderAssignment: UpdateSubpoenaDto, + ): Promise { + let defenderChoice = { ...defenderAssignment } + + if ( + defenderAssignment.defenderNationalId && + defenderAssignment.defenderChoice === DefenderChoice.CHOOSE + ) { + const lawyers = await this.lawyersService.getLawyers() + const chosenLawyer = lawyers.find( + (l) => l.SSN === defenderAssignment.defenderNationalId, + ) + if (!chosenLawyer) { + throw new NotFoundException('Lawyer not found') + } + + defenderChoice = { + ...defenderChoice, + ...{ + defenderName: chosenLawyer.Name, + defenderEmail: chosenLawyer.Email, + defenderPhoneNumber: chosenLawyer.Phone, + }, + } + } + + await this.patchSubpoenaDefender( + defendantNationalId, + caseId, + defenderChoice, + ) + + const updatedCase = await this.fetchCase(caseId, defendantNationalId) + + return SubpoenaResponse.fromInternalCaseResponse( + updatedCase, + defendantNationalId, + ) + } + + private async fetchCases( + nationalId: string, + ): Promise { try { const res = await fetch( `${this.config.backendUrl}/api/internal/cases/indictments`, @@ -163,32 +165,23 @@ export class CaseService { body: JSON.stringify({ nationalId }), }, ) - const response = await res.json() if (!res.ok) { throw new BadGatewayException( - response?.detail || - 'Unexpected error occurred while fetching all cases', + 'Unexpected error occurred while fetching cases', ) } - return this.format(response, lang) + return await res.json() } catch (reason) { - if (reason instanceof BadGatewayException) { - throw reason - } - - throw new BadGatewayException( - `Failed to fetch all cases: ${reason.message}`, - ) + throw new BadGatewayException(`Failed to fetch cases: ${reason.message}`) } } - private async getCase( + private async fetchCase( id: string, nationalId: string, - lang?: string, - ): Promise { + ): Promise { try { const res = await fetch( `${this.config.backendUrl}/api/internal/cases/indictment/${id}`, @@ -214,9 +207,7 @@ export class CaseService { ) } - const response = await res.json() - - return this.formatCase(response, lang) + return await res.json() } catch (reason) { if ( reason instanceof BadGatewayException || @@ -231,25 +222,48 @@ export class CaseService { } } - async getCases(nationalId: string, lang?: string): Promise { - return this.auditTrailService.audit( - 'digital-mailbox-api', - AuditedAction.GET_INDICTMENTS, - this.getAllCases(nationalId, lang), - nationalId, - ) - } + private async patchSubpoenaDefender( + defendantNationalId: string, + caseId: string, + defenderChoice: UpdateSubpoenaDto, + ): Promise { + try { + const response = await fetch( + `${this.config.backendUrl}/api/internal/case/${caseId}/defense/${defendantNationalId}`, + { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + authorization: `Bearer ${this.config.secretToken}`, + }, + body: JSON.stringify(defenderChoice), + }, + ) - async getCaseById( - id: string, - nationalId: string, - lang?: string, - ): Promise { - return this.auditTrailService.audit( - 'digital-mailbox-api', - AuditedAction.GET_INDICTMENT, - this.getCase(id, nationalId, lang), - () => id, - ) + if (!response.ok) { + const errorResponse = await response.json() + throw new BadGatewayException( + `Failed to assign defender: ${ + errorResponse.message || response.statusText + }`, + ) + } + + const updatedDefendant = + (await response.json()) as InternalDefendantResponse + + return { + id: updatedDefendant.id, + defenderChoice: updatedDefendant.defenderChoice, + defenderName: updatedDefendant.defenderName, + } as InternalDefendantResponse + } catch (error) { + if (error instanceof NotFoundException) { + throw error + } + throw new BadGatewayException( + error.message || 'An unexpected error occurred', + ) + } } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/dto/subpoena.dto.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/dto/subpoena.dto.ts new file mode 100644 index 000000000000..e8ef5b772ae9 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/dto/subpoena.dto.ts @@ -0,0 +1,17 @@ +import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator' + +import { ApiProperty } from '@nestjs/swagger' + +import { DefenderChoice } from '@island.is/judicial-system/types' + +export class UpdateSubpoenaDto { + @IsNotEmpty() + @IsEnum(DefenderChoice) + @ApiProperty({ enum: DefenderChoice }) + defenderChoice!: DefenderChoice + + @IsOptional() + @IsString() + @ApiProperty({ type: String }) + defenderNationalId?: string +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts index 921110188c86..122d51ba5589 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/case.response.ts @@ -1,5 +1,7 @@ import { ApiProperty } from '@nestjs/swagger' +import { InternalCaseResponse } from './internal/internalCase.response' + class IndictmentCaseData { @ApiProperty({ type: String }) caseNumber!: string @@ -30,4 +32,90 @@ class Items { export class CaseResponse { @ApiProperty({ type: Object }) data!: IndictmentCaseData + + static fromInternalCaseResponse( + res: InternalCaseResponse, + lang?: string, + ): CaseResponse { + const language = lang?.toLowerCase() + const defendant = res.defendants[0] + + return { + data: { + caseNumber: + language === 'en' + ? `Case number ${res.courtCaseNumber}` + : `Málsnúmer ${res.courtCaseNumber}`, + groups: [ + { + label: language === 'en' ? 'Defendant' : 'Varnaraðili', + items: [ + [language === 'en' ? 'Name' : 'Nafn', defendant.name], + [ + language === 'en' ? 'National ID' : 'Kennitala', + defendant.nationalId, + ], + [ + language === 'en' ? 'Address' : 'Heimilisfang', + defendant.address, + ], + ].map((item) => ({ + label: item[0] ?? '', + value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), + })), + }, + { + label: language === 'en' ? 'Defender' : 'Verjandi', + items: [ + [language === 'en' ? 'Name' : 'Nafn', defendant.defenderName], + [ + language === 'en' ? 'Email' : 'Netfang', + defendant.defenderEmail, + 'email', + ], + [ + language === 'en' ? 'Phone Nr.' : 'Símanúmer', + defendant.defenderPhoneNumber, + 'tel', + ], + ].map((item) => ({ + label: item[0] ?? '', + value: item[1] ?? (language === 'en' ? 'N/A' : 'Ekki skráð'), + linkType: item[2] ?? undefined, + })), + }, + { + label: language === 'en' ? 'Information' : 'Málsupplýsingar', + items: [ + { + label: language === 'en' ? 'Type' : 'Tegund', + value: language === 'en' ? 'Indictment' : 'Ákæra', + }, + { + label: + language === 'en' ? 'Case number' : 'Málsnúmer héraðsdóms', + value: res.courtCaseNumber, + }, + { + label: language === 'en' ? 'Court' : 'Dómstóll', + value: res.court.name, + }, + { + label: language === 'en' ? 'Judge' : 'Dómari', + value: res.judge.name, + }, + { + label: language === 'en' ? 'Institution' : 'Embætti', + value: res.prosecutorsOffice.name, + }, + { + label: language === 'en' ? 'Prosecutor' : 'Ákærandi', + value: res.prosecutor.name, + }, + ], + }, + ], + }, + } + } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts index 36b1db25739d..121a299fcbe1 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/cases.response.ts @@ -1,5 +1,9 @@ import { ApiProperty } from '@nestjs/swagger' +import { isCompletedCase } from '@island.is/judicial-system/types' + +import { InternalCasesResponse } from './internal/internalCases.response' + export class CasesResponse { @ApiProperty({ type: String }) id!: string @@ -15,4 +19,33 @@ export class CasesResponse { color: string label: string } + + static fromInternalCasesResponse( + response: InternalCasesResponse[], + lang?: string, + ): CasesResponse[] { + return response.map((item: InternalCasesResponse) => { + const language = lang?.toLowerCase() + + return { + id: item.id, + state: { + color: isCompletedCase(item.state) ? 'purple' : 'blue', + label: + language === 'en' + ? isCompletedCase(item.state) + ? 'Completed' + : 'Active' + : isCompletedCase(item.state) + ? 'Lokið' + : 'Í vinnslu', + }, + caseNumber: + language === 'en' + ? `Case number ${item.courtCaseNumber}` + : `Málsnúmer ${item.courtCaseNumber}`, + type: language === 'en' ? 'Indictment' : 'Ákæra', + } + }) + } } diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCase.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCase.response.ts new file mode 100644 index 000000000000..e01d1958d91a --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCase.response.ts @@ -0,0 +1,29 @@ +import { + DefenderChoice, + Gender, + Institution, + User, +} from '@island.is/judicial-system/types' + +export class InternalCaseResponse { + id!: string + courtCaseNumber!: string + defendants!: Defendant[] + court!: Institution + judge!: User + prosecutorsOffice!: Institution + prosecutor!: User +} + +interface Defendant { + nationalId?: string + name?: string + gender?: Gender + address?: string + citizenship?: string + defenderName?: string + defenderNationalId?: string + defenderEmail?: string + defenderPhoneNumber?: string + defenderChoice?: DefenderChoice +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCases.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCases.response.ts new file mode 100644 index 000000000000..145479becbf3 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalCases.response.ts @@ -0,0 +1,8 @@ +import { CaseState } from '@island.is/judicial-system/types' + +export class InternalCasesResponse { + id!: string + courtCaseNumber!: string + type!: string + state!: CaseState +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalDefendant.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalDefendant.response.ts new file mode 100644 index 000000000000..808519a0d05c --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internal/internalDefendant.response.ts @@ -0,0 +1,7 @@ +import { DefenderChoice } from '@island.is/judicial-system/types' + +export class InternalDefendantResponse { + id!: string + defenderChoice?: DefenderChoice + defenderName?: string +} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts deleted file mode 100644 index a72077190c97..000000000000 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCase.response.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' - -import { Defendant, Institution, User } from '@island.is/judicial-system/types' - -export class InternalCaseResponse { - @ApiProperty({ type: String }) - courtCaseNumber!: string - - @ApiProperty({ type: Object }) - defendants!: Defendant[] - - @ApiProperty({ type: Object }) - court!: Institution - - @ApiProperty({ type: Object }) - judge!: User - - @ApiProperty({ type: Object }) - prosecutorsOffice!: Institution - - @ApiProperty({ type: Object }) - prosecutor!: User -} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts deleted file mode 100644 index 84b653596213..000000000000 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/internalCases.response.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' - -import { CaseState } from '@island.is/judicial-system/types' - -export class InternalCasesResponse { - @ApiProperty({ type: String }) - id!: string - - @ApiProperty({ type: String }) - courtCaseNumber!: string - - @ApiProperty({ type: String }) - type!: string - - @ApiProperty({ type: String }) - state!: CaseState -} diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/subpoena.response.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/subpoena.response.ts new file mode 100644 index 000000000000..85330b5e6640 --- /dev/null +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/models/subpoena.response.ts @@ -0,0 +1,50 @@ +import { ApiProperty } from '@nestjs/swagger' + +import { formatNationalId } from '@island.is/judicial-system/formatters' +import { DefenderChoice } from '@island.is/judicial-system/types' + +import { InternalCaseResponse } from './internal/internalCase.response' + +class DefenderInfo { + @ApiProperty({ enum: () => DefenderChoice }) + defenderChoice?: DefenderChoice + + @ApiProperty({ type: () => String }) + defenderName?: string +} + +export class SubpoenaResponse { + @ApiProperty({ type: () => String }) + caseId!: string + + @ApiProperty({ type: () => String }) + displayInfo?: string + + @ApiProperty({ type: () => DefenderInfo }) + defenderInfo?: DefenderInfo + + static fromInternalCaseResponse( + internalCase: InternalCaseResponse, + defendantNationalId: string, + lang?: string, + ): SubpoenaResponse { + const formattedNationalId = formatNationalId(defendantNationalId) + + const defendantInfo = internalCase.defendants.find( + (defendant) => + defendant.nationalId === formattedNationalId || + defendant.nationalId === defendantNationalId, + ) + + return { + caseId: internalCase.id, + displayInfo: lang === 'en' ? 'Subpoena' : 'Þingbók', + defenderInfo: defendantInfo + ? { + defenderChoice: defendantInfo?.defenderChoice, + defenderName: defendantInfo?.defenderName, + } + : undefined, + } + } +} diff --git a/apps/judicial-system/web/src/components/FormProvider/case.graphql b/apps/judicial-system/web/src/components/FormProvider/case.graphql index a38e90c4fc42..6f2df8dfaa89 100644 --- a/apps/judicial-system/web/src/components/FormProvider/case.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/case.graphql @@ -20,7 +20,7 @@ query Case($input: CaseQueryInput!) { defenderNationalId defenderEmail defenderPhoneNumber - defendantWaivesRightToCounsel + defenderChoice defendantPlea serviceRequirement verdictViewDate diff --git a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql index 9e1c4e30fb2e..7e291a374a05 100644 --- a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql @@ -27,7 +27,7 @@ query LimitedAccessCase($input: CaseQueryInput!) { defenderNationalId defenderEmail defenderPhoneNumber - defendantWaivesRightToCounsel + defenderChoice verdictViewDate } defenderName diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Defender/SelectDefender.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Defender/SelectDefender.tsx index 451740313c4b..38da0dc3c098 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Defender/SelectDefender.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Defender/SelectDefender.tsx @@ -10,7 +10,10 @@ import { DefenderNotFound, FormContext, } from '@island.is/judicial-system-web/src/components' -import { Defendant } from '@island.is/judicial-system-web/src/graphql/schema' +import { + Defendant, + DefenderChoice, +} from '@island.is/judicial-system-web/src/graphql/schema' import { useDefendants } from '@island.is/judicial-system-web/src/utils/hooks' import { defender as m } from './Defender.strings' @@ -49,7 +52,10 @@ const SelectDefender: React.FC> = (props) => { defenderPhoneNumber: defendantWaivesRightToCounsel ? '' : defendant.defenderPhoneNumber, - defendantWaivesRightToCounsel, + defenderChoice: + defendantWaivesRightToCounsel === true + ? DefenderChoice.WAIVE + : undefined, } setAndSendDefendantToServer(updateDefendantInput, setWorkingCase) @@ -79,7 +85,7 @@ const SelectDefender: React.FC> = (props) => { accused: formatMessage(core.indictmentDefendant, { gender }), }), )} - checked={Boolean(defendant.defendantWaivesRightToCounsel)} + checked={Boolean(defendant.defenderChoice === DefenderChoice.WAIVE)} onChange={(event: React.ChangeEvent) => { toggleDefendantWaivesRightToCounsel( workingCase.id, @@ -92,7 +98,7 @@ const SelectDefender: React.FC> = (props) => { /> diff --git a/apps/judicial-system/web/src/routes/CourtOfAppeal/Cases/appealdCases.graphql b/apps/judicial-system/web/src/routes/CourtOfAppeal/Cases/appealdCases.graphql index 8d869557e9a0..06656feca08e 100644 --- a/apps/judicial-system/web/src/routes/CourtOfAppeal/Cases/appealdCases.graphql +++ b/apps/judicial-system/web/src/routes/CourtOfAppeal/Cases/appealdCases.graphql @@ -25,7 +25,7 @@ query AppealedCases($input: CaseListQueryInput) { nationalId name noNationalId - defendantWaivesRightToCounsel + defenderChoice } appealedDate initialRulingDate diff --git a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql index 36e8a9e69091..df7b8ee18f12 100644 --- a/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql +++ b/apps/judicial-system/web/src/routes/Defender/Cases/defenderCases.graphql @@ -22,7 +22,7 @@ query DefenderCases($input: CaseListQueryInput) { nationalId name noNationalId - defendantWaivesRightToCounsel + defenderChoice } initialRulingDate rulingDate diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql index a60971d44f0e..0fe071daaaa2 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/cases.graphql @@ -25,7 +25,7 @@ query Cases { nationalId name noNationalId - defendantWaivesRightToCounsel + defenderChoice verdictViewDate } courtDate diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql index e3235615b3d3..a7f734cc0b13 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql @@ -25,7 +25,7 @@ query PrisonCases { nationalId name noNationalId - defendantWaivesRightToCounsel + defenderChoice } courtDate isValidToDateInThePast diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/limitedAccessUpdateCase.graphql b/apps/judicial-system/web/src/utils/hooks/useCase/limitedAccessUpdateCase.graphql index ac23d6071e46..8b63cf9881b4 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/limitedAccessUpdateCase.graphql +++ b/apps/judicial-system/web/src/utils/hooks/useCase/limitedAccessUpdateCase.graphql @@ -27,7 +27,7 @@ mutation LimitedAccessUpdateCase($input: UpdateCaseInput!) { defenderNationalId defenderEmail defenderPhoneNumber - defendantWaivesRightToCounsel + defenderChoice } defenderName defenderNationalId diff --git a/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql b/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql index f9f3a850d7d6..5d88783a029f 100644 --- a/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql +++ b/apps/judicial-system/web/src/utils/hooks/useCase/updateCase.graphql @@ -20,7 +20,7 @@ mutation UpdateCase($input: UpdateCaseInput!) { defenderNationalId defenderEmail defenderPhoneNumber - defendantWaivesRightToCounsel + defenderChoice defendantPlea } defenderName diff --git a/apps/judicial-system/web/src/utils/mocks.ts b/apps/judicial-system/web/src/utils/mocks.ts index 5a1e4d803f32..83b75c15eb91 100644 --- a/apps/judicial-system/web/src/utils/mocks.ts +++ b/apps/judicial-system/web/src/utils/mocks.ts @@ -167,7 +167,7 @@ export const mockCase = (caseType: CaseType): Case => { name: 'Donald Duck', gender: Gender.MALE, address: 'Batcave 1337', - defendantWaivesRightToCounsel: false, + defenderChoice: null, }, ], defendantWaivesRightToCounsel: false, diff --git a/apps/judicial-system/web/src/utils/validate.ts b/apps/judicial-system/web/src/utils/validate.ts index ec4c2843d69b..8cba7111952a 100644 --- a/apps/judicial-system/web/src/utils/validate.ts +++ b/apps/judicial-system/web/src/utils/validate.ts @@ -9,6 +9,7 @@ import { CaseAppealState, CaseFileCategory, CaseType, + DefenderChoice, SessionArrangements, User, } from '@island.is/judicial-system-web/src/graphql/schema' @@ -422,7 +423,7 @@ export const isDefenderStepValid = (workingCase: Case): boolean => { const defendantsAreValid = () => workingCase.defendants?.every((defendant) => { return ( - defendant.defendantWaivesRightToCounsel || + defendant.defenderChoice === DefenderChoice.WAIVE || validate([ [defendant.defenderName, ['empty']], [defendant.defenderEmail, ['email-format']], diff --git a/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts b/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts index da2e10b99704..035e73ea6de7 100644 --- a/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts +++ b/libs/judicial-system/audit-trail/src/lib/auditTrail.service.ts @@ -53,6 +53,8 @@ export enum AuditedAction { CREATE_INDICTMENT_COUNT = 'CREATE_INDICTMENT_COUNT', UPDATE_INDICTMENT_COUNT = 'UPDATE_INDICTMENT_COUNT', DELETE_INDICTMENT_COUNT = 'DELETE_INDICTMENT_COUNT', + ASSIGN_DEFENDER_TO_SUBPOENA = 'ASSIGN_DEFENDER_TO_SUBPOENA', + GET_SUBPOENA = 'GET_SUBPOENA', } @Injectable() diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 4b6eb0e29d6c..d1f3fd51d23e 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -1,7 +1,6 @@ export { Feature } from './lib/feature' -export { Gender } from './lib/defendant' -export type { Defendant } from './lib/defendant' +export { Gender, DefenderChoice } from './lib/defendant' export { InstitutionType } from './lib/institution' export { NotificationType } from './lib/notification' export type { Institution } from './lib/institution' diff --git a/libs/judicial-system/types/src/lib/defendant.ts b/libs/judicial-system/types/src/lib/defendant.ts index 49b33c5eec6a..4d173e885d0b 100644 --- a/libs/judicial-system/types/src/lib/defendant.ts +++ b/libs/judicial-system/types/src/lib/defendant.ts @@ -4,20 +4,9 @@ export enum Gender { OTHER = 'OTHER', } -export interface Defendant { - id: string - created: string - modified: string - caseId: string - defendantWaivesRightToCounsel: boolean - noNationalId?: boolean - nationalId?: string - name?: string - gender?: Gender - address?: string - citizenship?: string - defenderName?: string - defenderNationalId?: string - defenderEmail?: string - defenderPhoneNumber?: string +export enum DefenderChoice { + WAIVE = 'WAIVE', // Waive right to counsel + CHOOSE = 'CHOOSE', // Choose defender + DELAY = 'DELAY', // Delay choice + DELEGATE = 'DELEGATE', // Delegate choice to judge } From c9801ffb73d4d02c31e725b8924a2cc3ab4faee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Tue, 4 Jun 2024 21:34:58 +0000 Subject: [PATCH 75/82] fix(j-s): Defender Case File Access (#15070) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixes defender case file access in indictments * Updates unit tests --------- Co-authored-by: Ívar Oddsson --- .../src/app/modules/case/case.service.ts | 10 ++-- .../modules/case/limitedAccessCase.service.ts | 11 ++++ .../guards/limitedAccessViewCaseFile.guard.ts | 51 ++++++++++--------- .../limitedAccessViewCaseFileGuard.spec.ts | 32 +----------- .../file/limitedAccessFile.controller.ts | 12 ++--- .../createCaseFileGuards.spec.ts | 11 ++-- .../createPresignedPostGuards.spec.ts | 9 +++- .../deleteCaseFileGuards.spec.ts | 13 +++-- .../limitedAccessFileControllerGuards.spec.ts | 5 +- 9 files changed, 74 insertions(+), 80 deletions(-) diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index 36465195d58d..408ad4b46bd6 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -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', @@ -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[] = [ diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index 6aeeaae0d7eb..bf2410586094 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -26,6 +26,7 @@ import { CaseState, CommentType, DateType, + EventType, NotificationType, UserRole, } from '@island.is/judicial-system/types' @@ -33,6 +34,7 @@ import { import { nowFactory, uuidFactory } from '../../factories' import { AwsS3Service } from '../aws-s3' import { Defendant, DefendantService } from '../defendant' +import { EventLog } from '../event-log' import { CaseFile, defenderCaseFileCategoriesForRestrictionAndInvestigationCases, @@ -111,6 +113,7 @@ export interface LimitedAccessUpdateCase | 'appealRulingDecision' > {} +const eventTypes = Object.values(EventType) const dateTypes = Object.values(DateType) const commentTypes = Object.values(CommentType) @@ -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', 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 0fa6e6fda3ce..3526675d6902 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 @@ -11,9 +11,8 @@ import { isCompletedCase, isDefenceUser, isIndictmentCase, - isInvestigationCase, isPrisonSystemUser, - isRestrictionCase, + isRequestCase, User, } from '@island.is/judicial-system/types' @@ -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 } } 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 dbe541817035..2deebedc9db4 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 @@ -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, @@ -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}`, - ) - }) - }, - ) - }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts b/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts index f62585f7be9f..3d8b09f65443 100644 --- a/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/file/limitedAccessFile.controller.ts @@ -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 { @@ -64,6 +59,7 @@ export class LimitedAccessFileController { @UseGuards( new CaseTypeGuard([...restrictionCases, ...investigationCases]), CaseWriteGuard, + CaseCompletedGuard, ) @RolesRules(defenderRule) @Post('file/url') @@ -84,6 +80,7 @@ export class LimitedAccessFileController { @UseGuards( new CaseTypeGuard([...restrictionCases, ...investigationCases]), CaseWriteGuard, + CaseCompletedGuard, LimitedAccessWriteCaseFileGuard, ) @RolesRules(defenderRule) @@ -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, @@ -126,6 +123,7 @@ export class LimitedAccessFileController { @UseGuards( new CaseTypeGuard([...restrictionCases, ...investigationCases]), CaseWriteGuard, + CaseCompletedGuard, CaseFileExistsGuard, LimitedAccessWriteCaseFileGuard, ) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFileGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFileGuards.spec.ts index a3325a93e8d8..b18200a5cb3e 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFileGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createCaseFileGuards.spec.ts @@ -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' @@ -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) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPostGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPostGuards.spec.ts index b842f3d9592f..6483025331da 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPostGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/createPresignedPostGuards.spec.ts @@ -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', () => { @@ -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) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFileGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFileGuards.spec.ts index 08fc526a564e..fb1e6b7eafb9 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFileGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/deleteCaseFileGuards.spec.ts @@ -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' @@ -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) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/limitedAccessFileControllerGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/limitedAccessFileControllerGuards.spec.ts index 27731303484a..f38b68b9a607 100644 --- a/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/limitedAccessFileControllerGuards.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/test/limitedAccessFileController/limitedAccessFileControllerGuards.spec.ts @@ -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', () => { @@ -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) }) }) From 19b919b2a936b4e0ae5abedec30505fd1104e0d8 Mon Sep 17 00:00:00 2001 From: jonarnarbriem <107482569+jonarnarbriem@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:28:29 +0000 Subject: [PATCH 76/82] feat(ids-api): remove delegation config for ver applications (#15081) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../auth-api-lib/src/lib/delegations/DelegationConfig.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libs/auth-api-lib/src/lib/delegations/DelegationConfig.ts b/libs/auth-api-lib/src/lib/delegations/DelegationConfig.ts index 09f17469b597..00c3dc1a81a4 100644 --- a/libs/auth-api-lib/src/lib/delegations/DelegationConfig.ts +++ b/libs/auth-api-lib/src/lib/delegations/DelegationConfig.ts @@ -77,15 +77,6 @@ export const DelegationConfig = defineConfig>({ DelegationType.Custom, ], }, - { - // The branch auth-api/custom-delegation-scope-rule is changing this, but it is not merged yet and this is required for release. - // Todo: add this to the scope migration of the branch - scopeName: '@island.is/applications/ver', - onlyForDelegationType: [ - DelegationType.ProcurationHolder, - DelegationType.Custom, - ], - }, { // The branch auth-api/custom-delegation-scope-rule is changing this, but it is not merged yet and this is required for release. // Todo: add this to the scope migration of the branch From eebb157182e0ef51de25c68a9779af0a25123ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0j=C3=B3n=20Gu=C3=B0j=C3=B3nsson?= Date: Wed, 5 Jun 2024 08:29:15 +0000 Subject: [PATCH 77/82] fix(j-s): Indictment Post Processing (#15077) * Fixes post processing of dismissed and cancelled indictments * Refactors code --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Court/Indictments/Completed/Completed.tsx | 58 +++++++++++-------- .../Indictments/Summary/Summary.strings.ts | 5 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx index b74b6ad4cb23..37e9619dec96 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx @@ -83,6 +83,13 @@ const Completed: FC = () => { [workingCase.id], ) + const isRulingOrFine = + workingCase.indictmentRulingDecision && + [ + CaseIndictmentRulingDecision.RULING, + CaseIndictmentRulingDecision.FINE, + ].includes(workingCase.indictmentRulingDecision) + const stepIsValid = () => workingCase.indictmentRulingDecision === CaseIndictmentRulingDecision.RULING ? workingCase.defendants?.every( @@ -112,30 +119,32 @@ const Completed: FC = () => { - - - - file.category === CaseFileCategory.CRIMINAL_RECORD_UPDATE, - )} - accept="application/pdf" - header={formatMessage(core.uploadBoxTitle)} - buttonLabel={formatMessage(core.uploadBoxButtonLabel)} - description={formatMessage(core.uploadBoxDescription, { - fileEndings: '.pdf', - })} - onChange={(files) => - handleCriminalRecordUpdateUpload( - files, - CaseFileCategory.CRIMINAL_RECORD_UPDATE, - ) - } - onRemove={(file) => handleRemoveFile(file)} - /> - + {isRulingOrFine && ( + + + + file.category === CaseFileCategory.CRIMINAL_RECORD_UPDATE, + )} + accept="application/pdf" + header={formatMessage(core.uploadBoxTitle)} + buttonLabel={formatMessage(core.uploadBoxButtonLabel)} + description={formatMessage(core.uploadBoxDescription, { + fileEndings: '.pdf', + })} + onChange={(files) => + handleCriminalRecordUpdateUpload( + files, + CaseFileCategory.CRIMINAL_RECORD_UPDATE, + ) + } + onRemove={(file) => handleRemoveFile(file)} + /> + + )} {workingCase.indictmentRulingDecision === CaseIndictmentRulingDecision.RULING && ( @@ -239,6 +248,7 @@ const Completed: FC = () => { Date: Wed, 5 Jun 2024 13:24:03 +0000 Subject: [PATCH 78/82] fix(fa): Renaming applied from applied to appliedDate (#15048) * adding sortable feature * Revert "adding sortable feature" This reverts commit d9691c54de2c2fb244cf89e49c0bfe6cd7857603. * adding more detail for api * removing white space break just adding html element to the db * renaming applied to applied_date * using applied date instead of applied * adding truncate and updating applied date * updating comment from code rabbit --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../dto/updateApplication.input.ts | 2 +- .../application/models/application.model.ts | 2 +- ...1145432-update-application-applied_date.js | 23 +++++++++++++++++++ .../application/application.service.ts | 4 ++-- .../application/dto/updateApplication.dto.ts | 2 +- .../application/models/application.model.ts | 2 +- .../modules/application/test/create.spec.ts | 14 +++++------ .../test/getCurrentApplication.spec.ts | 2 +- .../web-veita/graphql/sharedGql.ts | 10 ++++---- .../ApplicationsTable/ApplicationsTable.tsx | 5 ++-- .../components/Profile/ApplicationProfile.tsx | 6 ++--- .../web-veita/src/utils/navigation.ts | 6 ++--- .../src/utils/useApplicationState.ts | 6 ++--- libs/financial-aid/shared/src/lib/enums.ts | 2 +- .../shared/src/lib/interfaces.ts | 2 +- libs/financial-aid/shared/src/lib/utils.ts | 7 ++++++ 16 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 apps/financial-aid/backend/migrations/20240531145432-update-application-applied_date.js diff --git a/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts b/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts index e3ded3984884..d69d731f9512 100644 --- a/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts +++ b/apps/financial-aid/api/src/app/modules/application/dto/updateApplication.input.ts @@ -26,7 +26,7 @@ export class UpdateApplicationInput implements UpdateApplication { @Allow() @Field({ nullable: true }) - readonly applied?: string + readonly appliedDate?: string @Allow() @Field({ nullable: true }) diff --git a/apps/financial-aid/api/src/app/modules/application/models/application.model.ts b/apps/financial-aid/api/src/app/modules/application/models/application.model.ts index 6820c4ce1680..6ab17b7b2692 100644 --- a/apps/financial-aid/api/src/app/modules/application/models/application.model.ts +++ b/apps/financial-aid/api/src/app/modules/application/models/application.model.ts @@ -27,7 +27,7 @@ export class ApplicationModel implements Application { readonly modified!: string @Field() - readonly applied!: string + readonly appliedDate!: string @Field() readonly nationalId!: string diff --git a/apps/financial-aid/backend/migrations/20240531145432-update-application-applied_date.js b/apps/financial-aid/backend/migrations/20240531145432-update-application-applied_date.js new file mode 100644 index 000000000000..720d46d2103a --- /dev/null +++ b/apps/financial-aid/backend/migrations/20240531145432-update-application-applied_date.js @@ -0,0 +1,23 @@ +'use strict' + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => + Promise.all([ + queryInterface.renameColumn('applications', 'applied', 'applied_date', { + transaction: t, + }), + ]), + ) + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => + Promise.all([ + queryInterface.renameColumn('applications', 'applied_date', 'applied', { + transaction: t, + }), + ]), + ) + }, +} diff --git a/apps/financial-aid/backend/src/app/modules/application/application.service.ts b/apps/financial-aid/backend/src/app/modules/application/application.service.ts index 4c02909cf344..d5b7b7b63d2d 100644 --- a/apps/financial-aid/backend/src/app/modules/application/application.service.ts +++ b/apps/financial-aid/backend/src/app/modules/application/application.service.ts @@ -147,7 +147,7 @@ export class ApplicationService { spouseNationalId: nationalId, }, ], - applied: { [Op.gte]: firstDateOfMonth() }, + appliedDate: { [Op.gte]: firstDateOfMonth() }, }, }) @@ -295,7 +295,7 @@ export class ApplicationService { const appModel = await this.applicationModel.create({ ...application, - applied: nowFactory(), + appliedDate: nowFactory(), nationalId: application.nationalId || user.nationalId, }) diff --git a/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts b/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts index 03f82ebddfc2..75b7f3f3047e 100644 --- a/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts +++ b/apps/financial-aid/backend/src/app/modules/application/dto/updateApplication.dto.ts @@ -29,7 +29,7 @@ export class UpdateApplicationDto { @IsOptional() @IsString() @ApiProperty() - readonly applied?: string + readonly appliedDate?: string @IsOptional() @IsString() diff --git a/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts b/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts index cf12e6c028bf..9bbbbda00889 100644 --- a/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts +++ b/apps/financial-aid/backend/src/app/modules/application/models/application.model.ts @@ -54,7 +54,7 @@ export class ApplicationModel extends Model { allowNull: false, }) @ApiProperty() - applied: Date + appliedDate: Date @Column({ type: DataType.STRING, diff --git a/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts b/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts index 2fd79316df95..832cef72cd5a 100644 --- a/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts +++ b/apps/financial-aid/backend/src/app/modules/application/test/create.spec.ts @@ -145,7 +145,7 @@ describe('ApplicationController - Create', () => { expect(mockCreate).toHaveBeenCalledWith({ nationalId: user.nationalId, ...application, - applied: date, + appliedDate: date, }) }) @@ -160,7 +160,7 @@ describe('ApplicationController - Create', () => { spouseNationalId: user.nationalId, }, ], - applied: { [Op.gte]: firstDateOfMonth() }, + appliedDate: { [Op.gte]: firstDateOfMonth() }, }, }) }) @@ -232,7 +232,7 @@ describe('ApplicationController - Create', () => { id, state: application.state, created: new Date(), - applied: new Date(), + appliedDate: new Date(), email: application.email, } @@ -358,7 +358,7 @@ describe('ApplicationController - Create', () => { id, state: application.state, created: new Date(), - applied: new Date(), + appliedDate: new Date(), email: application.email, spouseEmail: application.spouseEmail, spouseName: application.spouseName, @@ -463,7 +463,7 @@ describe('ApplicationController - Create', () => { id, state: application.state, created: new Date(), - applied: new Date(), + appliedDate: new Date(), email: application.email, } @@ -565,7 +565,7 @@ describe('ApplicationController - Create', () => { id, state: application.state, created: new Date(), - applied: new Date(), + appliedDate: new Date(), email: application.email, } @@ -599,7 +599,7 @@ describe('ApplicationController - Create', () => { }) }) - describe('applicant has applied for period', () => { + describe('applicant has appliedDate for period', () => { let then: Then const id = uuid() diff --git a/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts b/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts index 9d17e9970e28..92416fbb4080 100644 --- a/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts +++ b/apps/financial-aid/backend/src/app/modules/application/test/getCurrentApplication.spec.ts @@ -56,7 +56,7 @@ describe('ApplicationController - Get current application', () => { spouseNationalId: user.nationalId, }, ], - applied: { [Op.gte]: firstDateOfMonth() }, + appliedDate: { [Op.gte]: firstDateOfMonth() }, }, }) }) diff --git a/apps/financial-aid/web-veita/graphql/sharedGql.ts b/apps/financial-aid/web-veita/graphql/sharedGql.ts index 0c7cf5cf95d8..482dd0b7a15b 100644 --- a/apps/financial-aid/web-veita/graphql/sharedGql.ts +++ b/apps/financial-aid/web-veita/graphql/sharedGql.ts @@ -7,7 +7,7 @@ export const ApplicationQuery = gql` applicationSystemId nationalId created - applied + appliedDate modified name phoneNumber @@ -151,7 +151,7 @@ export const UpdateApplicationTableMutation = gql` email modified created - applied + appliedDate state staff { name @@ -180,7 +180,7 @@ export const ApplicationsQuery = gql` email modified created - applied + appliedDate state staff { name @@ -211,7 +211,7 @@ export const ApplicationEventMutation = gql` nationalId created modified - applied + appliedDate name phoneNumber email @@ -332,7 +332,7 @@ export const UpdateApplicationMutation = gql` nationalId created modified - applied + appliedDate name phoneNumber email diff --git a/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx b/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx index 01be5e7cc62c..490b4dc66a40 100644 --- a/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx +++ b/apps/financial-aid/web-veita/src/components/ApplicationsTable/ApplicationsTable.tsx @@ -22,6 +22,7 @@ import { getStateUrlFromRoute, Routes, SortableTableHeaderProps, + truncateString, } from '@island.is/financial-aid/shared/lib' import { useAllApplications } from '@island.is/financial-aid-web/veita/src/utils/useAllApplications' @@ -81,7 +82,7 @@ const ApplicationsTable = ({ <> {application.staff?.name ? ( - {application.staff?.name} + {truncateString(application.staff?.name, 13)} ) : ( @@ -145,7 +146,7 @@ const ApplicationsTable = ({ ), TextTableItem( 'default', - getMonth(new Date(item.applied).getMonth()), + getMonth(new Date(item.appliedDate).getMonth()), ), assignButton(item), ]} diff --git a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx index c3634a406aa1..2295681ef1f0 100644 --- a/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx +++ b/apps/financial-aid/web-veita/src/components/Profile/ApplicationProfile.tsx @@ -96,8 +96,8 @@ const ApplicationProfile = ({ { title: 'Fyrir tímabilið', content: - getMonth(new Date(application.applied).getMonth()) + - format(new Date(application.applied), ' y'), + getMonth(new Date(application.appliedDate).getMonth()) + + format(new Date(application.appliedDate), ' y'), onclick: () => { setAppliedMonthModalVisible(true) }, @@ -337,7 +337,7 @@ const ApplicationProfile = ({ onVisibilityChange={(isVisibleBoolean) => { setAppliedMonthModalVisible(isVisibleBoolean) }} - appliedDate={application.applied} + appliedDate={application.appliedDate} createdDate={application.created} applicationId={application.id} setApplication={setApplication} diff --git a/apps/financial-aid/web-veita/src/utils/navigation.ts b/apps/financial-aid/web-veita/src/utils/navigation.ts index 9b43b783cbff..f83331caefe6 100644 --- a/apps/financial-aid/web-veita/src/utils/navigation.ts +++ b/apps/financial-aid/web-veita/src/utils/navigation.ts @@ -13,10 +13,10 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Tími án umsjár', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIED }, + { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIEDDATE }, { title: 'Umsjá', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], - defaultHeaderSort: ApplicationHeaderSortByEnum.APPLIED, + defaultHeaderSort: ApplicationHeaderSortByEnum.APPLIEDDATE, }, { group: 'Mitt', @@ -27,7 +27,7 @@ export const navigationItems = [ { title: 'Nafn', sortBy: ApplicationHeaderSortByEnum.NAME }, { title: 'Staða', sortBy: ApplicationHeaderSortByEnum.STATE }, { title: 'Síðast uppfært', sortBy: ApplicationHeaderSortByEnum.MODIFIED }, - { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIED }, + { title: 'Tímabil', sortBy: ApplicationHeaderSortByEnum.APPLIEDDATE }, { title: 'Unnið af', sortBy: ApplicationHeaderSortByEnum.STAFF }, ], defaultHeaderSort: ApplicationHeaderSortByEnum.MODIFIED, diff --git a/apps/financial-aid/web-veita/src/utils/useApplicationState.ts b/apps/financial-aid/web-veita/src/utils/useApplicationState.ts index f0e2d54385b2..351b472e3343 100644 --- a/apps/financial-aid/web-veita/src/utils/useApplicationState.ts +++ b/apps/financial-aid/web-veita/src/utils/useApplicationState.ts @@ -38,7 +38,7 @@ export const useApplicationState = () => { applicationId: string, event: ApplicationEventType, state?: ApplicationState, - applied?: Date, + appliedDate?: Date, rejection?: string, comment?: string, amount?: Amount, @@ -49,10 +49,10 @@ export const useApplicationState = () => { input: { id: applicationId, state, - applied, + appliedDate, rejection, comment, - staffId: applied ? undefined : admin?.staff?.id, + staffId: appliedDate ? undefined : admin?.staff?.id, event, amount, }, diff --git a/libs/financial-aid/shared/src/lib/enums.ts b/libs/financial-aid/shared/src/lib/enums.ts index 775cdb0f96e4..8fd34148166c 100644 --- a/libs/financial-aid/shared/src/lib/enums.ts +++ b/libs/financial-aid/shared/src/lib/enums.ts @@ -47,7 +47,7 @@ export enum ApplicationHeaderSortByEnum { MODIFIED = 'modified', CREATED = 'created', STAFF = 'staff', - APPLIED = 'applied', + APPLIEDDATE = 'appliedDate', } export enum ApplicationStateUrl { diff --git a/libs/financial-aid/shared/src/lib/interfaces.ts b/libs/financial-aid/shared/src/lib/interfaces.ts index f707e73f8778..c65518bfef28 100644 --- a/libs/financial-aid/shared/src/lib/interfaces.ts +++ b/libs/financial-aid/shared/src/lib/interfaces.ts @@ -334,7 +334,7 @@ export interface Application { id: string created: string modified: string - applied: string + appliedDate: string nationalId: string name: string phoneNumber?: string diff --git a/libs/financial-aid/shared/src/lib/utils.ts b/libs/financial-aid/shared/src/lib/utils.ts index 6d9f15d7d696..974a2d44a51a 100644 --- a/libs/financial-aid/shared/src/lib/utils.ts +++ b/libs/financial-aid/shared/src/lib/utils.ts @@ -126,3 +126,10 @@ export const addUserTypeDirectPayments = ( } }) } + +export const truncateString = (str: string, maxLength: number) => { + if (str.length > maxLength) { + return `${str.substring(0, maxLength)}...` + } + return str +} From 9e1ff00f9e4c6711c0cea8c48455f75a0e554d88 Mon Sep 17 00:00:00 2001 From: Herdis Maria Date: Wed, 5 Jun 2024 13:40:55 +0000 Subject: [PATCH 79/82] feat(ids-api): index delegations when IDS gets delegations (#15079) * index delegations when IDS gets delegations * fix tests * don't fail requests if indexing fails * mock delegation indexing in controller tests --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../delegations.controller.spec.ts | 38 +++++++++++++--- .../app/delegations/delegations.controller.ts | 45 ++++++++++++++----- .../src/app/delegations/delegations.module.ts | 8 +++- .../test/delegations-filters.spec.ts | 5 ++- .../test/delegations-scopes.spec.ts | 9 +++- 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts index fb560760dfc6..6f6e140cd772 100644 --- a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts +++ b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.spec.ts @@ -11,7 +11,7 @@ import { Delegation, DelegationDTO, DelegationProviderModel, - DelegationType, + DelegationsIndexService, DelegationTypeModel, Domain, InactiveReason, @@ -56,7 +56,7 @@ import { getScopePermission, personalRepresentativeType, } from '../../../test/stubs/personalRepresentativeStubs' -import { AuthDelegationProvider } from 'delegation' +import { AuthDelegationType, AuthDelegationProvider } from 'delegation' import { getPersonalRepresentativeDelegationType } from '@island.is/shared/types' describe('DelegationsController', () => { @@ -74,6 +74,7 @@ describe('DelegationsController', () => { let delegationTypeModel: typeof DelegationTypeModel let nationalRegistryApi: NationalRegistryClientService let delegationProviderModel: typeof DelegationProviderModel + let delegationIndexService: DelegationsIndexService const userNationalId = getFakeNationalId() @@ -125,6 +126,7 @@ describe('DelegationsController', () => { getModelToken(DelegationProviderModel), ) nationalRegistryApi = app.get(NationalRegistryClientService) + delegationIndexService = app.get(DelegationsIndexService) }) afterAll(async () => { @@ -223,6 +225,7 @@ describe('DelegationsController', () => { nationalRegistryErrors: number, ) => { let nationalRegistryApiSpy: jest.SpyInstance + let delegationIndexServiceSpy: jest.SpyInstance const validRepresentedPersons: NameIdTuple[] = [] const outdatedRepresentedPersons: NameIdTuple[] = [] const unactivatedRepresentedPersons: NameIdTuple[] = [] @@ -378,6 +381,10 @@ describe('DelegationsController', () => { return user ?? null }) + + delegationIndexServiceSpy = jest + .spyOn(delegationIndexService, 'indexDelegations') + .mockImplementation() }) afterAll(async () => { @@ -463,7 +470,8 @@ describe('DelegationsController', () => { it('should have the delegation type claims of PersonalRepresentative', () => { expect( body.every( - (d) => d.types[0] === DelegationType.PersonalRepresentative, + (d) => + d.types[0] === AuthDelegationType.PersonalRepresentative, ), ).toBeTruthy() }) @@ -500,6 +508,10 @@ describe('DelegationsController', () => { // Assert expect(expectedModels.length).toEqual(errorNationalIds.length) }) + + it('should index delegations', () => { + expect(delegationIndexServiceSpy).toHaveBeenCalled() + }) }) }, ) @@ -623,7 +635,7 @@ describe('DelegationsController', () => { beforeAll(async () => { response = await server.get(`${path}`).query({ fromNationalId: representeeNationalId, - delegationType: DelegationType.PersonalRepresentative, + delegationType: AuthDelegationType.PersonalRepresentative, }) body = response.body }) @@ -899,8 +911,13 @@ describe('DelegationsController', () => { const path = '/delegations' let response: request.Response let body: DelegationDTO[] + let delegationIndexServiceSpy: jest.SpyInstance beforeAll(async () => { + delegationIndexServiceSpy = jest + .spyOn(delegationIndexService, 'indexDelegations') + .mockImplementation() + response = await server.get(path) body = response.body }) @@ -956,7 +973,7 @@ describe('DelegationsController', () => { it('should have the delegation type claims of PersonalRepresentative', () => { expect( body.every( - (d) => d.type === DelegationType.PersonalRepresentative, + (d) => d.type === AuthDelegationType.PersonalRepresentative, ), ).toBeTruthy() }) @@ -993,6 +1010,10 @@ describe('DelegationsController', () => { // Assert expect(expectedModels.length).toEqual(errorNationalIds.length) }) + + it('should index delegations', () => { + expect(delegationIndexServiceSpy).toHaveBeenCalled() + }) }) }, ) @@ -1123,7 +1144,7 @@ describe('DelegationsController', () => { beforeAll(async () => { response = await server.get(`${path}`).query({ fromNationalId: representeeNationalId, - delegationType: DelegationType.PersonalRepresentative, + delegationType: AuthDelegationType.PersonalRepresentative, }) body = response.body }) @@ -1247,7 +1268,10 @@ describe('DelegationsController', () => { it('should return a single merged delegation', async () => { expect(body.length).toEqual(1) expect(body[0].types.sort()).toEqual( - [DelegationType.Custom, DelegationType.LegalGuardian].sort(), + [ + AuthDelegationType.Custom, + AuthDelegationType.LegalGuardian, + ].sort(), ) }) }) diff --git a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts index 6aed71ebf4b5..3cf848839ce6 100644 --- a/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts +++ b/apps/services/auth/ids-api/src/app/delegations/delegations.controller.ts @@ -1,6 +1,7 @@ import { Controller, Get, + Inject, ParseArrayPipe, Query, UseGuards, @@ -9,14 +10,16 @@ import { } from '@nestjs/common' import { ApiOkResponse, ApiTags } from '@nestjs/swagger' +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' import { DelegationDTO, DelegationScope, DelegationScopeService, DelegationsIncomingService, DelegationsService, - DelegationType, MergedDelegationDTO, + DelegationsIndexService, } from '@island.is/auth-api-lib' import type { User } from '@island.is/auth-nest-tools' import { @@ -25,6 +28,7 @@ import { Scopes, ScopesGuard, } from '@island.is/auth-nest-tools' +import { AuthDelegationType } from 'delegation' @UseGuards(IdsUserGuard, ScopesGuard) @ApiTags('delegations') @@ -34,16 +38,28 @@ import { }) export class DelegationsController { constructor( + @Inject(LOGGER_PROVIDER) + protected readonly logger: Logger, private readonly delegationsService: DelegationsService, private readonly delegationScopeService: DelegationScopeService, private readonly delegationsIncomingService: DelegationsIncomingService, + private readonly delegationIndexService: DelegationsIndexService, ) {} @Scopes('@identityserver.api/authentication') @Get() @ApiOkResponse({ isArray: true }) async findAllToV1(@CurrentUser() user: User): Promise { - return this.delegationsService.findAllIncoming(user) + const delegations = await this.delegationsService.findAllIncoming(user) + + // don't fail the request if indexing fails + try { + void this.delegationIndexService.indexDelegations(user) + } catch { + this.logger.error('Failed to index delegations') + } + + return delegations } @Scopes('@identityserver.api/authentication') @@ -58,10 +74,19 @@ export class DelegationsController { ) requestedScopes: Array, ): Promise { - return this.delegationsIncomingService.findAllAvailable({ + const delegations = await this.delegationsIncomingService.findAllAvailable({ user, requestedScopes, }) + + // don't fail the request if indexing fails + try { + void this.delegationIndexService.indexDelegations(user) + } catch { + this.logger.error('Failed to index delegations') + } + + return delegations } @Scopes('@identityserver.api/authentication') @@ -74,19 +99,19 @@ export class DelegationsController { 'delegationType', new ParseArrayPipe({ optional: true, items: String, separator: ',' }), ) - delegationType: Array, + delegationType: Array, ): Promise { const scopePromises = [] - if (delegationType.includes(DelegationType.ProcurationHolder)) + if (delegationType.includes(AuthDelegationType.ProcurationHolder)) scopePromises.push(this.delegationScopeService.findAllProcurationScopes()) - if (delegationType.includes(DelegationType.LegalGuardian)) + if (delegationType.includes(AuthDelegationType.LegalGuardian)) scopePromises.push( this.delegationScopeService.findAllLegalGuardianScopes(), ) - if (delegationType.includes(DelegationType.PersonalRepresentative)) + if (delegationType.includes(AuthDelegationType.PersonalRepresentative)) scopePromises.push( this.delegationScopeService.findPersonalRepresentativeScopes( user.nationalId, @@ -94,7 +119,7 @@ export class DelegationsController { ), ) - if (delegationType.includes(DelegationType.Custom)) + if (delegationType.includes(AuthDelegationType.Custom)) scopePromises.push( this.delegationScopeService .findAllValidCustomScopesTo(user.nationalId, fromNationalId) @@ -109,8 +134,8 @@ export class DelegationsController { if ( scopes.length > 0 || - delegationType.includes(DelegationType.ProcurationHolder) || - delegationType.includes(DelegationType.LegalGuardian) + delegationType.includes(AuthDelegationType.ProcurationHolder) || + delegationType.includes(AuthDelegationType.LegalGuardian) ) { scopes = [ ...scopes, diff --git a/apps/services/auth/ids-api/src/app/delegations/delegations.module.ts b/apps/services/auth/ids-api/src/app/delegations/delegations.module.ts index 3fdfcada9c54..50d68d49e2fb 100644 --- a/apps/services/auth/ids-api/src/app/delegations/delegations.module.ts +++ b/apps/services/auth/ids-api/src/app/delegations/delegations.module.ts @@ -7,6 +7,7 @@ import { } from '@island.is/auth-api-lib' import { DelegationsController } from './delegations.controller' +import { logger, LOGGER_PROVIDER } from '@island.is/logging' @Module({ imports: [ @@ -15,6 +16,11 @@ import { DelegationsController } from './delegations.controller' PersonalRepresentativeModule, ], controllers: [DelegationsController], - providers: [], + providers: [ + { + provide: LOGGER_PROVIDER, + useValue: logger, + }, + ], }) export class DelegationsModule {} diff --git a/apps/services/auth/ids-api/src/app/delegations/test/delegations-filters.spec.ts b/apps/services/auth/ids-api/src/app/delegations/test/delegations-filters.spec.ts index 8091acb47329..2728fde5eeb2 100644 --- a/apps/services/auth/ids-api/src/app/delegations/test/delegations-filters.spec.ts +++ b/apps/services/auth/ids-api/src/app/delegations/test/delegations-filters.spec.ts @@ -5,7 +5,7 @@ import faker from 'faker' import { setupWithAuth } from '../../../../test/setup' import { createNationalRegistryUser } from '@island.is/testing/fixtures' import { NationalRegistryClientService } from '@island.is/clients/national-registry-v2' -import { DelegationDTO } from '@island.is/auth-api-lib' +import { DelegationDTO, DelegationsIndexService } from '@island.is/auth-api-lib' import { RskRelationshipsClient } from '@island.is/clients-rsk-relationships' import { user } from './delegations-filters-types' import { Sequelize } from 'sequelize-typescript' @@ -20,6 +20,7 @@ describe('DelegationsController', () => { let factory: FixtureFactory let nationalRegistryApi: NationalRegistryClientService let rskApi: RskRelationshipsClient + let delegationIndexService: DelegationsIndexService beforeAll(async () => { app = await setupWithAuth({ @@ -29,6 +30,7 @@ describe('DelegationsController', () => { server = request(app.getHttpServer()) + delegationIndexService = app.get(DelegationsIndexService) nationalRegistryApi = app.get(NationalRegistryClientService) jest .spyOn(nationalRegistryApi, 'getIndividual') @@ -38,6 +40,7 @@ describe('DelegationsController', () => { name: faker.name.findName(), }), ) + jest.spyOn(delegationIndexService, 'indexDelegations').mockImplementation() rskApi = app.get(RskRelationshipsClient) diff --git a/apps/services/auth/ids-api/src/app/delegations/test/delegations-scopes.spec.ts b/apps/services/auth/ids-api/src/app/delegations/test/delegations-scopes.spec.ts index c7b2ecb927aa..c09fff631c6d 100644 --- a/apps/services/auth/ids-api/src/app/delegations/test/delegations-scopes.spec.ts +++ b/apps/services/auth/ids-api/src/app/delegations/test/delegations-scopes.spec.ts @@ -4,7 +4,10 @@ import faker from 'faker' import { Sequelize } from 'sequelize-typescript' import request from 'supertest' -import { DelegationType } from '@island.is/auth-api-lib' +import { + DelegationsIndexService, + DelegationType, +} from '@island.is/auth-api-lib' import { FixtureFactory } from '@island.is/services/auth/testing' import { createCurrentUser, @@ -89,6 +92,7 @@ describe('DelegationsController', () => { let app: TestApp let server: request.SuperTest let factory: FixtureFactory + let delegationIndexService: DelegationsIndexService beforeAll(async () => { app = await setupWithAuth({ @@ -99,6 +103,9 @@ describe('DelegationsController', () => { server = request(app.getHttpServer()) factory = new FixtureFactory(app) + + delegationIndexService = app.get(DelegationsIndexService) + jest.spyOn(delegationIndexService, 'indexDelegations').mockImplementation() }) afterAll(async () => { From bd9059b89169ff4c730be28dfe19fa03f53c67c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar=20Vestmann?= <43557895+RunarVestmann@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:57:48 +0000 Subject: [PATCH 80/82] feat(web): Organization page - prefilter search results (#15084) * When on an organization page, prefilter results * Show what is filtered by via tags * Change keys * Remove comments * Make sure that selected is an array --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/web/components/FilterTag/FilterTag.tsx | 8 +- apps/web/components/Header/Header.tsx | 12 +- apps/web/components/Menu/Menu.tsx | 3 + .../components/SearchInput/SearchInput.tsx | 61 ++-- apps/web/layouts/main.tsx | 7 + apps/web/screens/Search/Search.tsx | 285 ++++++++++-------- apps/web/utils/organization.ts | 16 +- 7 files changed, 232 insertions(+), 160 deletions(-) diff --git a/apps/web/components/FilterTag/FilterTag.tsx b/apps/web/components/FilterTag/FilterTag.tsx index 69a8f5b2ea70..19a59ba70b6a 100644 --- a/apps/web/components/FilterTag/FilterTag.tsx +++ b/apps/web/components/FilterTag/FilterTag.tsx @@ -1,17 +1,21 @@ -import { Tag, Box } from '@island.is/island-ui/core' import React from 'react' + +import { Box, Tag } from '@island.is/island-ui/core' + import * as styles from './FilterTag.css' interface FilterTagProps { onClick?: () => void + active?: boolean } export const FilterTag: React.FC> = ({ children, onClick, + active, }) => { return ( - + {children} diff --git a/apps/web/components/Header/Header.tsx b/apps/web/components/Header/Header.tsx index 5771b490d7de..b0ab4d768c57 100644 --- a/apps/web/components/Header/Header.tsx +++ b/apps/web/components/Header/Header.tsx @@ -1,4 +1,6 @@ /* eslint-disable jsx-a11y/anchor-is-valid */ +import React, { FC, useContext } from 'react' + import { Box, ButtonTypes, @@ -13,14 +15,14 @@ import { Logo, ResponsiveSpace, } from '@island.is/island-ui/core' +import { webMenuButtonClicked } from '@island.is/plausible' import { FixedNav, SearchInput } from '@island.is/web/components' -import { LoginButton } from './LoginButton' import { useI18n } from '@island.is/web/i18n' import { LayoutProps } from '@island.is/web/layouts/main' -import React, { FC, useContext } from 'react' + import { LanguageToggler } from '../LanguageToggler' import { Menu } from '../Menu/Menu' -import { webMenuButtonClicked } from '@island.is/plausible' +import { LoginButton } from './LoginButton' interface HeaderProps { showSearchInHeader?: boolean @@ -29,6 +31,7 @@ interface HeaderProps { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore make web strict megaMenuData + organizationSearchFilter?: string } const marginLeft = [1, 1, 1, 2] as ResponsiveSpace @@ -38,6 +41,7 @@ export const Header: FC> = ({ buttonColorScheme = 'default', megaMenuData, languageToggleQueryParams, + organizationSearchFilter, children, }) => { const { activeLocale, t } = useI18n() @@ -92,6 +96,7 @@ export const Header: FC> = ({ placeholder={t.searchPlaceholder} autocomplete={true} autosuggest={true} + organization={organizationSearchFilter} /> )} @@ -114,6 +119,7 @@ export const Header: FC> = ({ {...megaMenuData} buttonColorScheme={buttonColorScheme} onMenuOpen={webMenuButtonClicked} + organizationSearchFilter={organizationSearchFilter} /> diff --git a/apps/web/components/Menu/Menu.tsx b/apps/web/components/Menu/Menu.tsx index a4662e08f668..88a371db5243 100644 --- a/apps/web/components/Menu/Menu.tsx +++ b/apps/web/components/Menu/Menu.tsx @@ -28,6 +28,7 @@ interface Props { mainLinks: MegaMenuLink[] buttonColorScheme?: ButtonTypes['colorScheme'] onMenuOpen?: () => void + organizationSearchFilter?: string } const minarsidurLink = '/minarsidur/' @@ -39,6 +40,7 @@ export const Menu = ({ mainLinks, buttonColorScheme = 'default', onMenuOpen, + organizationSearchFilter, }: Props) => { const searchInput = useRef() const { activeLocale, t } = useI18n() @@ -146,6 +148,7 @@ export const Menu = ({ autosuggest={true} onRouting={closeModal} skipContext + organization={organizationSearchFilter} /> )} /> diff --git a/apps/web/components/SearchInput/SearchInput.tsx b/apps/web/components/SearchInput/SearchInput.tsx index cedfd7c1651d..62dd3ad5a18d 100644 --- a/apps/web/components/SearchInput/SearchInput.tsx +++ b/apps/web/components/SearchInput/SearchInput.tsx @@ -1,43 +1,44 @@ import React, { - useState, - useEffect, - useCallback, - useRef, forwardRef, ReactElement, + useCallback, + useEffect, useReducer, + useRef, + useState, } from 'react' -import Downshift from 'downshift' import { useMeasure } from 'react-use' +import Downshift from 'downshift' import { useRouter } from 'next/router' import { useApolloClient } from '@apollo/client/react' -import { GET_SEARCH_RESULTS_QUERY } from '@island.is/web/screens/queries' + import { AsyncSearchInput, + AsyncSearchInputProps, AsyncSearchSizes, Box, - Text, - Stack, Link, - AsyncSearchInputProps, + Stack, + Text, } from '@island.is/island-ui/core' +import { TestSupport } from '@island.is/island-ui/utils' +import { trackSearchQuery } from '@island.is/plausible' import { Locale } from '@island.is/shared/types' import { - GetSearchResultsQuery, - QuerySearchResultsArgs, - ContentLanguage, - Article, - SubArticle, - SearchableContentTypes, AnchorPage, + Article, + ContentLanguage, + GetSearchResultsQuery, + LifeEventPage, News, OrganizationSubpage, - LifeEventPage, + QuerySearchResultsArgs, + SearchableContentTypes, + SearchableTags, + SubArticle, } from '@island.is/web/graphql/schema' - import { LinkType, useLinkResolver } from '@island.is/web/hooks/useLinkResolver' -import { TestSupport } from '@island.is/island-ui/utils' -import { trackSearchQuery } from '@island.is/plausible' +import { GET_SEARCH_RESULTS_QUERY } from '@island.is/web/screens/queries' import { extractAnchorPageLinkType } from '@island.is/web/utils/anchorPage' import * as styles from './SearchInput.css' @@ -90,6 +91,7 @@ const useSearch = ( locale: Locale, term?: string, autocomplete?: boolean, + organization?: string, ): SearchState => { const [state, dispatch] = useReducer(searchReducer, initialSearchState) const client = useApolloClient() @@ -134,6 +136,9 @@ const useSearch = ( ], highlightResults: true, useQuery: 'suggestions', + tags: organization + ? [{ key: organization, type: SearchableTags.Organization }] + : undefined, }, }, }) @@ -169,7 +174,11 @@ type SubmitType = { string: string } -const useSubmit = (locale: Locale, onRouting?: () => void) => { +const useSubmit = ( + locale: Locale, + onRouting?: () => void, + organization?: string, +) => { const Router = useRouter() const { linkResolver } = useLinkResolver() @@ -183,6 +192,10 @@ const useSubmit = (locale: Locale, onRouting?: () => void) => { query.referencedBy = Router.query.referencedBy } + if (organization) { + query.organization = organization + } + Router.push({ ...(item.type === 'query' && { pathname: linkResolver('search').href, @@ -199,7 +212,7 @@ const useSubmit = (locale: Locale, onRouting?: () => void) => { onRouting() } }, - [Router, linkResolver, onRouting], + [Router, linkResolver, onRouting, organization], ) } @@ -217,6 +230,7 @@ interface SearchInputProps { onRouting?: () => void skipContext?: boolean quickContentLabel?: string + organization?: string } export const SearchInput = forwardRef< @@ -239,13 +253,14 @@ export const SearchInput = forwardRef< skipContext, quickContentLabel, dataTestId, + organization, }, ref, ) => { const [searchTerm, setSearchTerm] = useState(initialInputValue) - const search = useSearch(locale, searchTerm, autocomplete) + const search = useSearch(locale, searchTerm, autocomplete, organization) - const onSubmit = useSubmit(locale) + const onSubmit = useSubmit(locale, undefined, organization) const [hasFocus, setHasFocus] = useState(false) const onBlur = useCallback(() => setHasFocus(false), [setHasFocus]) const onFocus = useCallback(() => { diff --git a/apps/web/layouts/main.tsx b/apps/web/layouts/main.tsx index 07ae2743e7cc..4a3dda2ee68b 100644 --- a/apps/web/layouts/main.tsx +++ b/apps/web/layouts/main.tsx @@ -57,6 +57,7 @@ import { GET_CATEGORIES_QUERY, GET_NAMESPACE_QUERY } from '../screens/queries' import { GET_ALERT_BANNER_QUERY } from '../screens/queries/AlertBanner' import { GET_GROUPED_MENU_QUERY } from '../screens/queries/Menu' import { Screen } from '../types' +import { extractOrganizationSlugFromPathname } from '../utils/organization' import { formatMegaMenuCategoryLinks, formatMegaMenuLinks, @@ -246,6 +247,11 @@ const Layout: Screen = ({ const isServiceWeb = pathIsRoute(router.asPath, 'serviceweb', activeLocale) + const organizationSearchFilter = extractOrganizationSlugFromPathname( + router.asPath, + activeLocale, + ) + return ( @@ -403,6 +409,7 @@ const Layout: Screen = ({ showSearchInHeader={showSearchInHeader} megaMenuData={megaMenuData} languageToggleQueryParams={languageToggleQueryParams} + organizationSearchFilter={organizationSearchFilter} /> )} diff --git a/apps/web/screens/Search/Search.tsx b/apps/web/screens/Search/Search.tsx index 600c813dcf5b..f788cfc1b250 100644 --- a/apps/web/screens/Search/Search.tsx +++ b/apps/web/screens/Search/Search.tsx @@ -92,7 +92,7 @@ interface CategoryProps { page: number searchResults: GetSearchResultsDetailedQuery['searchResults'] countResults: GetSearchCountTagsQuery['searchResults'] - namespace: GetNamespaceQuery['getNamespace'] + namespace: Record referencedByTitle?: string } @@ -137,7 +137,7 @@ const connectedTypes: Partial< webManual: ['WebManual', 'WebManualChapterItem'], } -const stringToArray = (value: string | string[]) => +const stringToArray = (value: string | string[] | undefined) => Array.isArray(value) ? value : value?.length ? [value] : [] const Search: Screen = ({ @@ -153,14 +153,8 @@ const Search: Screen = ({ ...initialState, query: { q, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict type: stringToArray(query.type) as SearchableContentTypes[], - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict category: stringToArray(query.category), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict organization: stringToArray(query.organization), }, }) @@ -173,8 +167,6 @@ const Search: Screen = ({ const { activeLocale } = useI18n() const searchRef = useRef(null) const routerReplace = useRouterReplace() - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict const n = useNamespace(namespace) const { linkResolver } = useLinkResolver() @@ -227,27 +219,17 @@ const Search: Screen = ({ const getLabels = (item: SearchEntryType) => { const labels = [] - switch (item.__typename) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict + switch (item.__typename as string | undefined) { case 'LifeEventPage': labels.push(n('lifeEvent')) break - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict case 'News': labels.push(n('newsTitle')) break - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict case 'AdgerdirPage': labels.push(n('adgerdirTitle')) break - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict case 'ManualChapterItem': - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore make web strict labels.push(item.manualChapter.title) break default: @@ -452,32 +434,36 @@ const Search: Screen = ({ } } - const categories: CategoriesProps[] = [ - { - id: 'category', - label: n('categories', 'Þjónustuflokkar'), - selected: state.query.category ?? [], - singleOption: true, - filters: (countResults?.tagCounts ?? []) - .filter((x) => x.value.trim() && x.type === 'category') - .map(({ key, value }) => ({ - label: value, - value: key, - })), - }, - { - id: 'organization', - label: n('organizations', 'Opinberir aðilar'), - selected: state.query.organization ?? [], - singleOption: true, - filters: (countResults?.tagCounts ?? []) - .filter((x) => x.value.trim() && x.type === 'organization') - .map(({ key, value }) => ({ - label: value, - value: key, - })), - }, - ] + const categories: CategoriesProps[] = useMemo( + () => [ + { + id: 'category', + label: n('categories', 'Þjónustuflokkar'), + selected: stringToArray(state.query.category), + singleOption: true, + filters: (countResults?.tagCounts ?? []) + .filter((x) => x.value.trim() && x.type === 'category') + .map(({ key, value }) => ({ + label: value, + value: key, + })), + }, + { + id: 'organization', + label: n('organizations', 'Opinberir aðilar'), + selected: stringToArray(state.query.organization), + singleOption: true, + filters: (countResults?.tagCounts ?? []) + .filter((x) => x.value.trim() && x.type === 'organization') + .map(({ key, value }) => ({ + label: value, + value: key, + })), + }, + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [countResults?.tagCounts, state.query.category, state.query.organization], + ) const filterLabels: FilterLabels = { labelClearAll: n('labelClearAll', 'Hreinsa allar síur'), @@ -491,6 +477,49 @@ const Search: Screen = ({ const [referencedBy, setReferencedBy] = useQueryState('referencedBy') + const filterTags = useMemo(() => { + const filterTags: { label: string; onClick: () => void }[] = [] + + if (referencedBy && referencedByTitle) { + filterTags.push({ + label: referencedByTitle, + onClick: () => { + dispatch({ + type: ActionType.SET_PARAMS, + payload: { + referencedBy: null, + }, + }) + }, + }) + } + + for (const category of categories) { + for (const selectedCategory of category.selected) { + const label = category.filters.find( + (c) => c.value === selectedCategory, + )?.label + filterTags.push({ + label: typeof label === 'string' ? label : selectedCategory, + onClick: () => { + dispatch({ + type: ActionType.SET_PARAMS, + payload: { + query: { + [category.id]: category.selected.filter( + (c) => c !== selectedCategory, + ), + }, + }, + }) + }, + }) + } + } + + return filterTags + }, [categories, referencedBy, referencedByTitle]) + return ( <> @@ -537,109 +566,103 @@ const Search: Screen = ({ 0 ? 'top' : 'center'} space={3} flexWrap="nowrap" collapseBelow="md" > - {referencedBy && ( - - {referencedByTitle && ( + + {filterTags.length > 0 && ( + {n( - 'referencedByPrefix', + 'filteredByPrefix', activeLocale === 'is' ? 'Síað eftir' : 'Filtered by', )} : - )} - { - setReferencedBy(null) - dispatch({ - type: ActionType.RESET_SEARCH, - }) - }} - > - {referencedByTitle || - n( - 'clearSearchFilters', - activeLocale === 'is' - ? 'Hreinsa síu' - : 'Clear filters', - )} - - - )} - {!referencedBy && ( - - {countResults.total > 0 && ( - { - dispatch({ - type: ActionType.RESET_SEARCH, - }) - }} - > - {n('showAllResults', 'Sýna allt')} - - )} - {tagsList - .filter((x) => x.count > 0) - .map(({ title, key }, index) => ( + + {filterTags.map((tag) => ( + + {tag.label} + + ))} + + + )} + {!referencedBy && ( + + {countResults.total > 0 && ( { dispatch({ - type: ActionType.SET_PARAMS, - payload: { - query: { - processentry: false, - ...getSearchParams(key), - category: [], - organization: [], - }, - searchLocked: false, - }, + type: ActionType.RESET_SEARCH, }) }} > - {title} - - ))} - {typeof countResults.processEntryCount == 'number' && - countResults.processEntryCount > 0 && ( - { - dispatch({ - type: ActionType.SET_PARAMS, - payload: { - query: { - processentry: true, - ...getSearchParams('webArticle'), - }, - searchLocked: false, - }, - }) - }} - > - {n('processEntry', 'Umsóknir')} + {n('showAllResults', 'Sýna allt')} )} - - )} - + {tagsList + .filter((x) => x.count > 0) + .map(({ title, key }) => ( + { + dispatch({ + type: ActionType.SET_PARAMS, + payload: { + query: { + processentry: false, + ...getSearchParams(key), + category: [], + organization: [], + }, + searchLocked: false, + }, + }) + }} + > + {title} + + ))} + {typeof countResults.processEntryCount == 'number' && + countResults.processEntryCount > 0 && ( + { + dispatch({ + type: ActionType.SET_PARAMS, + payload: { + query: { + processentry: true, + ...getSearchParams('webArticle'), + }, + searchLocked: false, + }, + }) + }} + > + {n('processEntry', 'Umsóknir')} + + )} + + )} + - {total} niðurstöður + {total} {total === 1 ? 'niðurstaða' : 'niðurstöður'} {' '} - fundust á ensku. + {total === 1 ? 'fannst' : 'fundust'} á ensku. ) diff --git a/apps/web/utils/organization.ts b/apps/web/utils/organization.ts index eec4959d238f..be9cbb93ff83 100644 --- a/apps/web/utils/organization.ts +++ b/apps/web/utils/organization.ts @@ -1,7 +1,8 @@ import { Locale } from 'locale' import { OrganizationPage, OrganizationTheme } from '../graphql/schema' -import { linkResolver } from '../hooks' +import { linkResolver, pathIsRoute } from '../hooks' +import { isLocale } from '../i18n/I18n' // TODO: Perhaps add this functionality to the linkResolver export const getOrganizationLink = ( @@ -46,3 +47,16 @@ export const getBackgroundStyle = ( linear-gradient(180deg, rgba(0,0,0,0.5) 0%, rgba(0, 0, 0, 0) 70%)` return background.backgroundColor ?? '' } + +export const extractOrganizationSlugFromPathname = ( + pathname: string, + locale: Locale, +) => { + const isOrganizationPage = pathIsRoute(pathname, 'organizations', locale) + if (!isOrganizationPage) { + return '' + } + const segments = pathname.split('/').filter((x) => x) + const localeSegment = isLocale(segments[0]) ? segments[0] : '' + return (localeSegment ? segments[2] : segments[1]) ?? '' +} From ec2035c75e4215049ec4c15abf952f9e137000c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar=20Vestmann?= <43557895+RunarVestmann@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:28:21 +0000 Subject: [PATCH 81/82] feat(web): Ultraviolet Radiation chart - Add endpoint that shows past year measurements (#15087) * Add endpoint that shows past year * Fix typo --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../statistics/src/lib/statistics.service.ts | 16 ++++++++-- .../src/lib/ultraviolet-radiation.service.ts | 32 ++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/libs/clients/statistics/src/lib/statistics.service.ts b/libs/clients/statistics/src/lib/statistics.service.ts index b37d989ab770..4e2638cec32a 100644 --- a/libs/clients/statistics/src/lib/statistics.service.ts +++ b/libs/clients/statistics/src/lib/statistics.service.ts @@ -6,7 +6,8 @@ import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' import { LATEST_MEASUREMENT_KEY as LATEST_UV_MEASUREMENT_KEY, - MEASUREMENT_SERIES_KEY as UV_MEASUREMENT_SERIES_KEY, + MEASUREMENT_SERIES_PAST_72_HOURS_KEY as UV_MEASUREMENT_SERIES_PAST_72_HOURS_KEY, + MEASUREMENT_SERIES_PAST_YEAR_KEY as UV_MEASUREMENT_SERIES_PAST_YEAR_KEY, UltravioletRadiationClientService, } from '@island.is/clients/ultraviolet-radiation' @@ -42,8 +43,17 @@ export class StatisticsClientService { if (query.sourceDataKeys.includes(LATEST_UV_MEASUREMENT_KEY)) { promises.push(this.ultravioletRadiationService.getLatestMeasurement()) } - if (query.sourceDataKeys.includes(UV_MEASUREMENT_SERIES_KEY)) { - promises.push(this.ultravioletRadiationService.getMeasurementSeries()) + if ( + query.sourceDataKeys.includes(UV_MEASUREMENT_SERIES_PAST_72_HOURS_KEY) + ) { + promises.push( + this.ultravioletRadiationService.getMeasurementSeriesPast72Hours(), + ) + } + if (query.sourceDataKeys.includes(UV_MEASUREMENT_SERIES_PAST_YEAR_KEY)) { + promises.push( + this.ultravioletRadiationService.getMeasurementSeriesPastYear(), + ) } const [csvSourceData, ...rest] = await Promise.all(promises) diff --git a/libs/clients/ultraviolet-radiation/src/lib/ultraviolet-radiation.service.ts b/libs/clients/ultraviolet-radiation/src/lib/ultraviolet-radiation.service.ts index 7ed2db40ad54..5812cf9a17a8 100644 --- a/libs/clients/ultraviolet-radiation/src/lib/ultraviolet-radiation.service.ts +++ b/libs/clients/ultraviolet-radiation/src/lib/ultraviolet-radiation.service.ts @@ -7,8 +7,10 @@ import { export const LATEST_MEASUREMENT_KEY = 'icelandicRadiationSafetyAuthority.ultravioletRadiation.latestMeasurement' as const -export const MEASUREMENT_SERIES_KEY = - 'icelandicRadiationSafetyAuthority.ultravioletRadiation.measurementSeries' as const +export const MEASUREMENT_SERIES_PAST_72_HOURS_KEY = + 'icelandicRadiationSafetyAuthority.ultravioletRadiation.measurementSeriesPast72Hours' as const +export const MEASUREMENT_SERIES_PAST_YEAR_KEY = + 'icelandicRadiationSafetyAuthority.ultravioletRadiation.measurementSeriesPastYear' as const export const isValidMeasurement = ( item: InlineResponse2001BodyDataLatest | undefined, @@ -23,9 +25,8 @@ export class UltravioletRadiationClientService { async getLatestMeasurement(): Promise< StatisticSourceData > { - const response = await this.api.returnDailyUV() - const measurement = - response?.body?.dataLatest ?? response?.body?.dataAll?.at(-1) + const response = await this.api.returnHourlyUV() + const measurement = response?.body?.dataAll?.at(-1) if (!isValidMeasurement(measurement)) { return { data: { @@ -45,14 +46,29 @@ export class UltravioletRadiationClientService { } } - async getMeasurementSeries(): Promise< - StatisticSourceData + async getMeasurementSeriesPast72Hours(): Promise< + StatisticSourceData > { const response = await this.api.returnHourlyUV() const series = response.body?.dataAll?.filter(isValidMeasurement) ?? [] return { data: { - [MEASUREMENT_SERIES_KEY]: series.map((measurement) => ({ + [MEASUREMENT_SERIES_PAST_72_HOURS_KEY]: series.map((measurement) => ({ + header: String(Date.parse(measurement.time)), + value: measurement.uvVal, + })), + }, + } + } + + async getMeasurementSeriesPastYear(): Promise< + StatisticSourceData + > { + const response = await this.api.returnDailyUV() + const series = response.body?.dataAll?.filter(isValidMeasurement) ?? [] + return { + data: { + [MEASUREMENT_SERIES_PAST_YEAR_KEY]: series.map((measurement) => ({ header: String(Date.parse(measurement.time)), value: measurement.uvVal, })), From 543857af15f49bd1ba83edd56ae6e5f09058b82e Mon Sep 17 00:00:00 2001 From: veronikasif <54938148+veronikasif@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:38:24 +0000 Subject: [PATCH 82/82] feat(ui-fields): Add spacing to CheckboxFormField (#15108) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- libs/application/core/src/lib/fieldBuilders.ts | 2 ++ libs/application/types/src/lib/Fields.ts | 1 + .../ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx | 2 ++ 3 files changed, 5 insertions(+) diff --git a/libs/application/core/src/lib/fieldBuilders.ts b/libs/application/core/src/lib/fieldBuilders.ts index fe5a1bc8ec2b..f177d23bcd03 100644 --- a/libs/application/core/src/lib/fieldBuilders.ts +++ b/libs/application/core/src/lib/fieldBuilders.ts @@ -89,6 +89,7 @@ export function buildCheckboxField( large = true, required, backgroundColor = 'blue', + spacing, } = data return { ...extractCommonFields(data), @@ -98,6 +99,7 @@ export function buildCheckboxField( backgroundColor, options, required, + spacing, type: FieldTypes.CHECKBOX, component: FieldComponents.CHECKBOX, } diff --git a/libs/application/types/src/lib/Fields.ts b/libs/application/types/src/lib/Fields.ts index 51eedf9ed822..945b9202707d 100644 --- a/libs/application/types/src/lib/Fields.ts +++ b/libs/application/types/src/lib/Fields.ts @@ -232,6 +232,7 @@ export interface CheckboxField extends BaseField { required?: boolean backgroundColor?: InputBackgroundColor onSelect?: ((s: string[]) => void) | undefined + spacing?: 0 | 1 | 2 } export interface DateField extends BaseField { diff --git a/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx b/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx index acd393180915..136d978de23a 100644 --- a/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx +++ b/libs/application/ui-fields/src/lib/CheckboxFormField/CheckboxFormField.tsx @@ -38,6 +38,7 @@ export const CheckboxFormField: FC> = ({ width, required, onSelect, + spacing, } = field const { formatMessage } = useLocale() @@ -76,6 +77,7 @@ export const CheckboxFormField: FC> = ({ } strong={strong} error={error} + spacing={spacing} options={finalOptions?.map( ({ label, subLabel, rightContent, tooltip, ...o }) => ({ ...o,