From c507751eeda5e013657f28f212e647e5aa75a1dc Mon Sep 17 00:00:00 2001 From: nilsarne Date: Mon, 9 Dec 2024 14:40:41 +0100 Subject: [PATCH 1/8] =?UTF-8?q?POC=20for=20bruk=20av=20Gotenberg=20til=20?= =?UTF-8?q?=C3=A5=20generere=20PDF=20av=20s=C3=B8knad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nais/fyllut/config.yaml | 2 + .nais/fyllut/dev-delingslenke.yaml | 3 + .nais/fyllut/dev.yaml | 3 + .nais/fyllut/preprod-alt.yaml | 3 + .nais/fyllut/preprod.yaml | 3 + .nais/fyllut/prod.yaml | 3 + mocks/mocks/routes/skjemabygging-proxy.js | 2 +- packages/fyllut-backend/icons/nav-logo.svg | 3 + packages/fyllut-backend/src/config/config.ts | 2 + packages/fyllut-backend/src/config/types.d.ts | 1 + .../routers/api/{exstream.ts => gotenberg.ts} | 10 +- .../src/routers/api/helpers/htmlBuilder.ts | 4 + .../src/routers/api/helpers/pdfService.ts | 157 +++++++++++------- .../fyllut-backend/src/routers/api/index.js | 4 +- .../src/routers/api/send-inn-utfylt-soknad.ts | 2 +- 15 files changed, 131 insertions(+), 71 deletions(-) create mode 100644 packages/fyllut-backend/icons/nav-logo.svg rename packages/fyllut-backend/src/routers/api/{exstream.ts => gotenberg.ts} (89%) diff --git a/.nais/fyllut/config.yaml b/.nais/fyllut/config.yaml index 068fb037f..da85187a2 100644 --- a/.nais/fyllut/config.yaml +++ b/.nais/fyllut/config.yaml @@ -87,6 +87,8 @@ spec: value: {{skjemabygging-proxy-url}} - name: SKJEMABYGGING_PROXY_CLIENT_ID value: {{skjemabygging-proxy-client-id}} + - name: GOTENBERG_URL + value: {{gotenberg-url}} - name: SEND_INN_TOKEN_X_CLIENT_ID value: {{send-inn-token-x-client-id}} - name: SEND_INN_HOST diff --git a/.nais/fyllut/dev-delingslenke.yaml b/.nais/fyllut/dev-delingslenke.yaml index d1760bf3b..43051d3d9 100644 --- a/.nais/fyllut/dev-delingslenke.yaml +++ b/.nais/fyllut/dev-delingslenke.yaml @@ -8,6 +8,7 @@ foersteside-url: https://www.nav.no/soknader/api/forsteside dekorator-url: https://www.nav.no/dekoratoren?simple=true skjemabygging-proxy-client-id: 95170319-b4d7-4190-8271-118ed19bafbf skjemabygging-proxy-url: https://skjemabygging-proxy.dev-fss-pub.nais.io +gotenberg-url: http://upload-convert-to-pdf.fyllut-sendinn send-inn-token-x-client-id: dev-gcp:team-soknad:innsending-api send-inn-host: http://innsending-api.team-soknad forms-api-url: https://forms-api.nav.no @@ -46,6 +47,8 @@ accessPolicy: - application: nav-dekoratoren namespace: personbruker cluster: dev-gcp + - application: upload-convert-to-pdf + namespace: fyllut-sendinn external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/dev.yaml b/.nais/fyllut/dev.yaml index f9d5dd64d..04da4d1b0 100644 --- a/.nais/fyllut/dev.yaml +++ b/.nais/fyllut/dev.yaml @@ -8,6 +8,7 @@ foersteside-url: https://www.nav.no/soknader/api/forsteside dekorator-url: https://www.nav.no/dekoratoren?simple=true skjemabygging-proxy-client-id: 95170319-b4d7-4190-8271-118ed19bafbf skjemabygging-proxy-url: https://skjemabygging-proxy.dev-fss-pub.nais.io +gotenberg-url: http://upload-convert-to-pdf.fyllut-sendinn send-inn-token-x-client-id: dev-gcp:team-soknad:innsending-api send-inn-host: http://innsending-api.team-soknad kodeverk: @@ -40,6 +41,8 @@ accessPolicy: - application: forms-api namespace: fyllut-sendinn cluster: dev-gcp + - application: upload-convert-to-pdf + namespace: fyllut-sendinn external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/preprod-alt.yaml b/.nais/fyllut/preprod-alt.yaml index c0c6e5ce7..45a211d64 100644 --- a/.nais/fyllut/preprod-alt.yaml +++ b/.nais/fyllut/preprod-alt.yaml @@ -9,6 +9,7 @@ foersteside-url: https://www.nav.no/soknader/api/forsteside dekorator-url: https://www.nav.no/dekoratoren?simple=true skjemabygging-proxy-client-id: 95170319-b4d7-4190-8271-118ed19bafbf skjemabygging-proxy-url: https://skjemabygging-proxy.dev-fss-pub.nais.io +gotenberg-url: http://upload-convert-to-pdf.fyllut-sendinn send-inn-token-x-client-id: dev-gcp:team-soknad:innsending-api send-inn-host: http://innsending-api.team-soknad kodeverk: @@ -47,6 +48,8 @@ accessPolicy: - application: forms-api namespace: fyllut-sendinn cluster: dev-gcp + - application: upload-convert-to-pdf + namespace: fyllut-sendinn external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/preprod.yaml b/.nais/fyllut/preprod.yaml index c807ea709..b85c06962 100644 --- a/.nais/fyllut/preprod.yaml +++ b/.nais/fyllut/preprod.yaml @@ -9,6 +9,7 @@ foersteside-url: https://www.nav.no/soknader/api/forsteside dekorator-url: https://www.nav.no/dekoratoren?simple=true skjemabygging-proxy-client-id: 95170319-b4d7-4190-8271-118ed19bafbf skjemabygging-proxy-url: https://skjemabygging-proxy.dev-fss-pub.nais.io +gotenberg-url: http://upload-convert-to-pdf.fyllut-sendinn send-inn-token-x-client-id: dev-gcp:team-soknad:innsending-api send-inn-host: http://innsending-api.team-soknad kodeverk: @@ -48,6 +49,8 @@ accessPolicy: - application: forms-api namespace: fyllut-sendinn cluster: dev-gcp + - application: upload-convert-to-pdf + namespace: fyllut-sendinn external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/prod.yaml b/.nais/fyllut/prod.yaml index 8f00fc36d..d16cabb2b 100644 --- a/.nais/fyllut/prod.yaml +++ b/.nais/fyllut/prod.yaml @@ -8,6 +8,7 @@ foersteside-url: https://www.nav.no/soknader/api/forsteside dekorator-url: https://www.nav.no/dekoratoren?simple=true skjemabygging-proxy-client-id: 031863f2-9881-44af-ace5-6b5ab52afeb1 skjemabygging-proxy-url: https://skjemabygging-proxy.prod-fss-pub.nais.io +gotenberg-url: http://upload-convert-to-pdf.fyllut-sendinn send-inn-token-x-client-id: prod-gcp:team-soknad:innsending-api send-inn-host: http://innsending-api.team-soknad kodeverk: @@ -45,6 +46,8 @@ accessPolicy: - application: forms-api namespace: fyllut-sendinn cluster: prod-gcp + - application: upload-convert-to-pdf + namespace: fyllut-sendinn external: - host: skjemabygging-proxy.prod-fss-pub.nais.io - host: formio-api.intern.nav.no diff --git a/mocks/mocks/routes/skjemabygging-proxy.js b/mocks/mocks/routes/skjemabygging-proxy.js index 18bf7ed7c..1ebcdf1b2 100644 --- a/mocks/mocks/routes/skjemabygging-proxy.js +++ b/mocks/mocks/routes/skjemabygging-proxy.js @@ -1,7 +1,7 @@ module.exports = [ { id: 'post-exstream-pdf', - url: '/skjemabygging-proxy/exstream', + url: '/skjemabygging-proxy/gotenberg', method: 'POST', variants: [ { diff --git a/packages/fyllut-backend/icons/nav-logo.svg b/packages/fyllut-backend/icons/nav-logo.svg new file mode 100644 index 000000000..f5677fbc3 --- /dev/null +++ b/packages/fyllut-backend/icons/nav-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/fyllut-backend/src/config/config.ts b/packages/fyllut-backend/src/config/config.ts index e7f9914bc..6bdddc589 100644 --- a/packages/fyllut-backend/src/config/config.ts +++ b/packages/fyllut-backend/src/config/config.ts @@ -79,6 +79,7 @@ const localDevelopmentConfig: DefaultConfig = { decoratorUrl: 'https://www.nav.no/dekoratoren?simple=true', skjemabyggingProxyUrl: process.env.SKJEMABYGGING_PROXY_URL || 'https://skjemabygging-proxy.dev-fss-pub.nais.io', skjemabyggingProxyClientId: '95170319-b4d7-4190-8271-118ed19bafbf', + gotenbergUrl: process.env.GOTENBERG_URL || 'https://upload-convert-to-pdf.fyllut-sendinn', azureOpenidTokenEndpoint: process.env.AZURE_OPENID_CONFIG_TOKEN_ENDPOINT || 'https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/oauth2/v2.0/token', @@ -125,6 +126,7 @@ const defaultConfig: DefaultConfig = { decoratorUrl: process.env.DECORATOR_URL!, skjemabyggingProxyUrl: process.env.SKJEMABYGGING_PROXY_URL!, skjemabyggingProxyClientId: process.env.SKJEMABYGGING_PROXY_CLIENT_ID!, + gotenbergUrl: process.env.GOTENBERG_URL!, azureOpenidTokenEndpoint: process.env.AZURE_OPENID_CONFIG_TOKEN_ENDPOINT!, clientId: process.env.AZURE_APP_CLIENT_ID!, skjemaDir: process.env.SKJEMA_DIR!, diff --git a/packages/fyllut-backend/src/config/types.d.ts b/packages/fyllut-backend/src/config/types.d.ts index 8281a23c4..b4cc4aa2b 100644 --- a/packages/fyllut-backend/src/config/types.d.ts +++ b/packages/fyllut-backend/src/config/types.d.ts @@ -43,6 +43,7 @@ export type DefaultConfig = { decoratorUrl: string; skjemabyggingProxyUrl: string; skjemabyggingProxyClientId: string; + gotenbergUrl: string; azureOpenidTokenEndpoint: string; clientId: string; skjemaDir?: string; diff --git a/packages/fyllut-backend/src/routers/api/exstream.ts b/packages/fyllut-backend/src/routers/api/gotenberg.ts similarity index 89% rename from packages/fyllut-backend/src/routers/api/exstream.ts rename to packages/fyllut-backend/src/routers/api/gotenberg.ts index e2884a5c3..81c6d7bf1 100644 --- a/packages/fyllut-backend/src/routers/api/exstream.ts +++ b/packages/fyllut-backend/src/routers/api/gotenberg.ts @@ -6,7 +6,6 @@ import { Submission, } from '@navikt/skjemadigitalisering-shared-domain'; import { NextFunction, Request, Response } from 'express'; -import { base64Decode } from '../../utils/base64'; import { htmlResponseError } from '../../utils/errorHandling'; import { logErrorWithStacktrace } from '../../utils/errors'; import { createPdf } from './helpers/pdfService'; @@ -28,7 +27,7 @@ const parseBody = ( return { form, submission, submissionMethod, translations, language }; }; -const exstream = { +const gotenberg = { post: async (req: Request, res: Response, next: NextFunction) => { try { const { form, submission, submissionMethod, translations, language } = parseBody(req); @@ -42,8 +41,9 @@ const exstream = { translations, languageCode, ); - res.contentType(pdf.contentType); - res.send(base64Decode(pdf.data)); + + res.setHeader('Content-Type', 'application/pdf'); + res.status(200).send(Buffer.from(new Uint8Array(pdf))); } catch (e) { logErrorWithStacktrace(e as Error); const createPdfError = htmlResponseError('Generering av PDF feilet'); @@ -52,4 +52,4 @@ const exstream = { }, }; -export default exstream; +export default gotenberg; diff --git a/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts b/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts index eae10d32f..86e02f585 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts @@ -73,15 +73,19 @@ p {margin: 0} .alt {margin-bottom: 5px; font-family: "Courier New", sans-serif; font-style: italic;} .innrykk {margin: 0px 0px 10px 20px;} .underskrift {margin-bottom: 30px;} +.navlogored {height: 16px;float: left;margin: 4px auto 2px auto;} `; const body = (formSummaryObject: SummaryPanel[], confirmation?: string, signatures?: string) => ` +${navlogo} ${formSummaryObject.map(section).join('')} ${confirmation || ''} ${signatures || ''} `; +const navlogo: string = `NAV logo`; + const section = (formSection: SummaryPanel) => `

${formSection.label}

${sectionContent(formSection.components, 1)}`; diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index 336538250..855e70623 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -6,16 +6,16 @@ import { translationUtils, } from '@navikt/skjemadigitalisering-shared-domain'; import correlator from 'express-correlation-id'; +import FormData from 'form-data'; +import { readFileSync } from 'fs'; +import path from 'path'; import { config } from '../../../config/config'; import { logger } from '../../../logger'; import { appMetrics } from '../../../services'; -import { base64Decode, base64Encode } from '../../../utils/base64'; -import { responseToError, synchronousResponseToError } from '../../../utils/errorHandling'; +import { synchronousResponseToError } from '../../../utils/errorHandling'; import fetchWithRetry, { HeadersInit } from '../../../utils/fetchWithRetry'; import { createHtmlFromSubmission } from './htmlBuilder'; -const { skjemabyggingProxyUrl, gitVersion } = config; - export const createPdfAsByteArray = async ( accessToken: string, form: NavFormType, @@ -24,8 +24,7 @@ export const createPdfAsByteArray = async ( translations: I18nTranslationMap, language: string, ) => { - const pdf = await createPdf(accessToken, form, submission, submissionMethod, translations, language); - return Array.from(base64Decode(pdf.data) ?? []); + return await createPdfFromGotenberg(accessToken, form, submission, submissionMethod, translations, language); }; export const createPdf = async ( @@ -35,6 +34,47 @@ export const createPdf = async ( submissionMethod: string, translations: I18nTranslationMap, language: string, +) => { + const pdf = await createPdfFromGotenberg(accessToken, form, submission, submissionMethod, translations, language); + return Buffer.from(new Uint8Array(pdf)); +}; + +const footer: string = + '\n' + + '\n' + + ' \n' + + '\n' + + '\n' + + '

Generert 16. Nov 2024 kl 14:30:

\n' + + '

av

\n' + + '\n' + + ''; + +const filePath = path.join(process.cwd(), '/icons/nav-logo.svg'); + +const navIcon = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); + +export const createPdfFromGotenberg = async ( + accessToken: string, + form: NavFormType, + submission: Submission, + submissionMethod: string, + translations: I18nTranslationMap, + language: string, ) => { const translate = (text: string, textReplacements?: I18nTranslationReplacements) => translationUtils.translateWithTextReplacements({ @@ -48,88 +88,81 @@ export const createPdf = async ( if (!html || Object.keys(html).length === 0) { throw Error('Missing HTML for generating PDF.'); } - const { fodselsnummerDNummerSoker } = submission.data; + //const { fodselsnummerDNummerSoker } = submission.data; appMetrics.exstreamPdfRequestsCounter.inc(); let errorOccurred = false; const stopMetricRequestDuration = appMetrics.outgoingRequestDuration.startTimer({ - service: 'exstream', - method: 'createPdf', + service: 'gotenberg', + method: 'createPdfFromGotenberg', }); + const assets = {}; + const options = { pdfa: true, pdfua: true }; + const gotenbergUrl = config.gotenbergUrl; try { - return await createPdfFromHtml( - accessToken, - translate(form.title), - form.properties.skjemanummer, - language, - html, - (fodselsnummerDNummerSoker as string | undefined) || '—', - ); + return await createPdfCallingGotenberg(accessToken, gotenbergUrl, html, assets, options); } catch (e) { errorOccurred = true; appMetrics.exstreamPdfFailuresCounter.inc(); throw e; } finally { const durationSeconds = stopMetricRequestDuration({ error: String(errorOccurred) }); - logger.info(`Request to exstream pdf service completed after ${durationSeconds} seconds`, { + logger.info(`Request to gotenberg pdf service completed after ${durationSeconds} seconds`, { error: errorOccurred, durationSeconds, }); } }; -export const createPdfFromHtml = async ( +const createPdfCallingGotenberg = async ( azureAccessToken: string, - title: string, - skjemanummer: string, - language: string, + gotenbergUrl: string, html: string, - pid: string, -) => { - const response = await fetchWithRetry(`${skjemabyggingProxyUrl}/exstream`, { + assets: { [filename: string]: string }, + options: { pdfa: boolean; pdfua: boolean }, +): Promise => { + const formData = new FormData(); + + // Add the main HTML content + formData.append('files', Buffer.from(html), 'index.html'); + formData.append('files', Buffer.from(footer), 'footer.html'); + if (navIcon != null) { + formData.append('files', Buffer.from(navIcon), 'Nav-logo.svg'); + } + + // Add optional assets like logos, footers, etc. + for (const [filename, content] of Object.entries(assets)) { + formData.append('files', Buffer.from(content), filename); + } + + // Add Gotenberg-specific options + formData.append('pdfa', options.pdfa ? 'PDF/A-1b' : ''); + formData.append('pdfua', options.pdfua ? 'true' : ''); + formData.append('skipNetworkIdleEvent', 'false'); + + // Send the request to Gotenberg + const gotenbergResponse = await fetchWithRetry(`${gotenbergUrl}/forms/chromium/convert/html`, { retry: 3, headers: { - Authorization: `Bearer ${azureAccessToken}`, + ...formData.getHeaders(), + //Authorization: `Bearer ${azureAccessToken}`, 'x-correlation-id': correlator.getId(), - 'Content-Type': 'application/json', } as HeadersInit, method: 'POST', - body: JSON.stringify({ - content: { - contentType: 'application/json', - data: base64Encode( - JSON.stringify({ - dokumentTittel: title, - spraakkode: language, - blankettnr: skjemanummer, - brukersFnr: pid, - skjemaversjon: gitVersion, - html: base64Encode(html), - }), - ), - async: 'true', - }, - RETURNFORMAT: 'PDF', - RETURNDATA: 'TRUE', - }), + body: formData, }); - if (response.ok) { - const json: any = await response.json(); - if (!json.data?.result?.[0]?.content) { - if (json.data?.id) { - throw synchronousResponseToError( - `Feil i responsdata fra Exstream på id "${json.data?.id}"`, - json, - response.status, - response.url, - true, - ); - } else { - throw synchronousResponseToError('Feil i responsdata fra Exstream', json, response.status, response.url, true); - } - } - return json.data.result[0].content; + if (!gotenbergResponse.ok) { + const errorText = await gotenbergResponse.text(); + console.error('Gotenberg error response:', errorText); + throw synchronousResponseToError( + `Feil i responsdata fra Gotenberg på id "${correlator.getId()}"`, + errorText, + gotenbergResponse.status, + gotenbergResponse.url, + true, + ); } - throw await responseToError(response, 'Feil ved generering av PDF hos Exstream', true); + const pdfBuffer = gotenbergResponse.arrayBuffer(); + return pdfBuffer; }; diff --git a/packages/fyllut-backend/src/routers/api/index.js b/packages/fyllut-backend/src/routers/api/index.js index 39397335f..5b4f76f54 100644 --- a/packages/fyllut-backend/src/routers/api/index.js +++ b/packages/fyllut-backend/src/routers/api/index.js @@ -9,11 +9,11 @@ import { initApiConfig } from './api-helper'; import commonCodes from './common-codes'; import config from './config'; import enhetsliste from './enhetsliste.js'; -import exstream from './exstream'; import form from './form'; import forms from './forms'; import forsteside from './forsteside'; import globalTranslations from './global-translations.js'; +import gotenberg from './gotenberg'; import log from './log'; import mottaksadresser from './mottaksadresser.js'; import pdl from './pdl'; @@ -47,7 +47,7 @@ apiRouter.post('/send-inn/soknad', tokenxSendInn, sendInnSoknad.post); apiRouter.put('/send-inn/soknad', tokenxSendInn, sendInnSoknad.put); apiRouter.put('/send-inn/utfyltsoknad', azureSkjemabyggingProxy, tokenxSendInn, sendInnUtfyltSoknad.put); apiRouter.get('/common-codes/archive-subjects', kodeverkToken, commonCodes.getArchiveSubjects); -apiRouter.post('/pdf/convert', azureSkjemabyggingProxy, exstream.post); +apiRouter.post('/pdf/convert', azureSkjemabyggingProxy, gotenberg.post); apiRouter.get('/common-codes/currencies', kodeverkToken, commonCodes.getCurrencies); apiRouter.post('/log/:level', rateLimiter(60000, 60), log.post); apiRouter.get('/health/status', status.get); diff --git a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts index e7dca33cf..6c075a84d 100644 --- a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts +++ b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts @@ -33,7 +33,7 @@ const sendInnUtfyltSoknad = { next(new Error(errorMessage)); return; } - + logger.warning('***** Skal konvertere søknad til PDF ******'); const pdfByteArray = await createPdfAsByteArray( req.headers.AzureAccessToken as string, form, From 9d14a3c16dcd0539412cdc56b3cebaadbec5ecca Mon Sep 17 00:00:00 2001 From: nilsarne Date: Thu, 19 Dec 2024 16:05:34 +0100 Subject: [PATCH 2/8] =?UTF-8?q?POC=20for=20bruk=20av=20Gotenberg=20til=20?= =?UTF-8?q?=C3=A5=20generere=20PDF=20av=20s=C3=B8knad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nais/fyllut/dev-delingslenke.yaml | 1 + .nais/fyllut/dev.yaml | 1 + .nais/fyllut/preprod-alt.yaml | 1 + .nais/fyllut/preprod.yaml | 1 + .nais/fyllut/prod.yaml | 1 + mocks/mocks/collections.json | 2 +- mocks/mocks/routes/skjemabygging-proxy.js | 4 +- packages/fyllut-backend/src/app.test.ts | 2 +- packages/fyllut-backend/src/config/config.ts | 4 +- .../src/routers/api/exstream.test.ts | 45 ------------------ .../routers/api/helpers/footer-template.html | 46 +++++++++++++++++++ .../src/routers/api/helpers/footerBuilder.ts | 31 +++++++++++++ .../src/routers/api/helpers/htmlBuilder.ts | 4 +- .../src/routers/api/helpers/pdfService.ts | 44 ++++++------------ .../fyllut-backend/src/routers/api/index.js | 2 +- .../api/send-inn-utfylt-soknad.test.ts | 6 +-- .../src/routers/api/send-inn-utfylt-soknad.ts | 2 +- .../src/texts/statiskeTekster.js | 8 ++++ 18 files changed, 118 insertions(+), 87 deletions(-) delete mode 100644 packages/fyllut-backend/src/routers/api/exstream.test.ts create mode 100644 packages/fyllut-backend/src/routers/api/helpers/footer-template.html create mode 100644 packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts diff --git a/.nais/fyllut/dev-delingslenke.yaml b/.nais/fyllut/dev-delingslenke.yaml index 43051d3d9..c2831d9f2 100644 --- a/.nais/fyllut/dev-delingslenke.yaml +++ b/.nais/fyllut/dev-delingslenke.yaml @@ -49,6 +49,7 @@ accessPolicy: cluster: dev-gcp - application: upload-convert-to-pdf namespace: fyllut-sendinn + cluster: dev-gcp external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/dev.yaml b/.nais/fyllut/dev.yaml index 04da4d1b0..6a4f1e599 100644 --- a/.nais/fyllut/dev.yaml +++ b/.nais/fyllut/dev.yaml @@ -43,6 +43,7 @@ accessPolicy: cluster: dev-gcp - application: upload-convert-to-pdf namespace: fyllut-sendinn + cluster: dev-gcp external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/preprod-alt.yaml b/.nais/fyllut/preprod-alt.yaml index 45a211d64..ed5bf2887 100644 --- a/.nais/fyllut/preprod-alt.yaml +++ b/.nais/fyllut/preprod-alt.yaml @@ -50,6 +50,7 @@ accessPolicy: cluster: dev-gcp - application: upload-convert-to-pdf namespace: fyllut-sendinn + cluster: dev-gcp external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/preprod.yaml b/.nais/fyllut/preprod.yaml index b85c06962..e62815982 100644 --- a/.nais/fyllut/preprod.yaml +++ b/.nais/fyllut/preprod.yaml @@ -51,6 +51,7 @@ accessPolicy: cluster: dev-gcp - application: upload-convert-to-pdf namespace: fyllut-sendinn + cluster: dev-gcp external: - host: skjemabygging-proxy.dev-fss-pub.nais.io - host: formio-api.intern.dev.nav.no diff --git a/.nais/fyllut/prod.yaml b/.nais/fyllut/prod.yaml index d16cabb2b..1432b5b1d 100644 --- a/.nais/fyllut/prod.yaml +++ b/.nais/fyllut/prod.yaml @@ -48,6 +48,7 @@ accessPolicy: cluster: prod-gcp - application: upload-convert-to-pdf namespace: fyllut-sendinn + cluster: prod-gcp external: - host: skjemabygging-proxy.prod-fss-pub.nais.io - host: formio-api.intern.nav.no diff --git a/mocks/mocks/collections.json b/mocks/mocks/collections.json index 0375f9cf7..4e51b2c23 100644 --- a/mocks/mocks/collections.json +++ b/mocks/mocks/collections.json @@ -7,7 +7,7 @@ "get-translations:success", "post-azure-openid-token:success", "get-kodeverk-currencies:success", - "post-exstream-pdf:success", + "post-gotenberg-pdf:success", "get-tokenx-endpoint:success", "post-tokenx:success", "post-soknad:success", diff --git a/mocks/mocks/routes/skjemabygging-proxy.js b/mocks/mocks/routes/skjemabygging-proxy.js index 1ebcdf1b2..6dde09cc9 100644 --- a/mocks/mocks/routes/skjemabygging-proxy.js +++ b/mocks/mocks/routes/skjemabygging-proxy.js @@ -1,7 +1,7 @@ module.exports = [ { - id: 'post-exstream-pdf', - url: '/skjemabygging-proxy/gotenberg', + id: 'post-gotenberg-pdf', + url: '/skjemabygging-proxy/extream', method: 'POST', variants: [ { diff --git a/packages/fyllut-backend/src/app.test.ts b/packages/fyllut-backend/src/app.test.ts index 8bf8d793c..5717484e3 100644 --- a/packages/fyllut-backend/src/app.test.ts +++ b/packages/fyllut-backend/src/app.test.ts @@ -253,7 +253,7 @@ describe('app', () => { .post(extractPath(azureTokenEndpoint)) .reply(200, { access_token: 'azure-access-token' }); const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL as string) - .post('/exstream') + .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const tokenxWellKnownScope = nock(extractHost(tokenxConfig?.wellKnownUrl)) .get(extractPath(tokenxConfig?.wellKnownUrl)) diff --git a/packages/fyllut-backend/src/config/config.ts b/packages/fyllut-backend/src/config/config.ts index 6bdddc589..c484963ec 100644 --- a/packages/fyllut-backend/src/config/config.ts +++ b/packages/fyllut-backend/src/config/config.ts @@ -79,7 +79,7 @@ const localDevelopmentConfig: DefaultConfig = { decoratorUrl: 'https://www.nav.no/dekoratoren?simple=true', skjemabyggingProxyUrl: process.env.SKJEMABYGGING_PROXY_URL || 'https://skjemabygging-proxy.dev-fss-pub.nais.io', skjemabyggingProxyClientId: '95170319-b4d7-4190-8271-118ed19bafbf', - gotenbergUrl: process.env.GOTENBERG_URL || 'https://upload-convert-to-pdf.fyllut-sendinn', + gotenbergUrl: process.env.GOTENBERG_URL || 'https://convert-to-pdf.intern.dev.nav.no', azureOpenidTokenEndpoint: process.env.AZURE_OPENID_CONFIG_TOKEN_ENDPOINT || 'https://login.microsoftonline.com/966ac572-f5b7-4bbe-aa88-c76419c0f851/oauth2/v2.0/token', @@ -173,4 +173,4 @@ const checkConfigConsistency = (config: ConfigType, logError = logger.error, exi } }; -export { checkConfigConsistency, config }; +export { checkConfigConsistency, config, defaultConfig }; diff --git a/packages/fyllut-backend/src/routers/api/exstream.test.ts b/packages/fyllut-backend/src/routers/api/exstream.test.ts deleted file mode 100644 index 42a235e9c..000000000 --- a/packages/fyllut-backend/src/routers/api/exstream.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import nock from 'nock'; -import { mockRequest, mockResponse } from '../../test/testHelpers'; -import { base64Decode } from '../../utils/base64'; -import exstream from './exstream'; - -const formTitle = 'testskjema'; -const defaultBody = { - form: JSON.stringify({ title: formTitle, components: [], properties: { skjemanummer: 'NAV 12.34-56' } }), - submission: JSON.stringify({ data: {} }), - submissionMethod: 'paper', - translations: JSON.stringify({}), - language: 'nb-NO', -}; - -describe('exstream', () => { - it('decodes and sends the pdf on success', async () => { - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL as string) - .post('/exstream') - .reply(200, { data: { result: [{ content: { data: 'base64EncodedPDFstring' } }] } }); - const req = mockRequest({ headers: { AzureAccessToken: 'azure-access-token' }, body: defaultBody }); - const res = mockResponse(); - const next = vi.fn(); - await exstream.post(req, res, next); - expect(next).not.toHaveBeenCalled(); - expect(res.send).toHaveBeenCalledWith(base64Decode('base64EncodedPDFstring')); - skjemabyggingproxyScope.done(); - }); - - it('calls next if skjemabygging-proxy returns error', async () => { - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL as string) - .post('/exstream') - .reply(500, 'error body'); - const req = mockRequest({ headers: { AzureAccessToken: 'azure-access-token' }, body: defaultBody }); - const res = mockResponse(); - const next = vi.fn(); - await exstream.post(req, res, next); - - expect(next).toHaveBeenCalledTimes(1); - const error = next.mock.calls[0][0]; - expect(error?.message).toBe('Generering av PDF feilet'); - expect(error?.render_html).toBe(true); - expect(res.send).not.toHaveBeenCalled(); - skjemabyggingproxyScope.done(); - }); -}); diff --git a/packages/fyllut-backend/src/routers/api/helpers/footer-template.html b/packages/fyllut-backend/src/routers/api/helpers/footer-template.html new file mode 100644 index 000000000..96c3700d5 --- /dev/null +++ b/packages/fyllut-backend/src/routers/api/helpers/footer-template.html @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts new file mode 100644 index 000000000..a3854ee36 --- /dev/null +++ b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts @@ -0,0 +1,31 @@ +import { TEXTS } from '@navikt/skjemadigitalisering-shared-domain'; +import { readFileSync } from 'fs'; +import path from 'path'; + +const filePath = path.join(process.cwd(), '/src/routers/api/helpers/footer-template.html'); + +export async function generateFooterHtml( + userId, + schemaVersion, + skjemanummer, + language, + translate: (text: string) => string, +) { + let footerHtml = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); + + const creationDate = new Date().toLocaleString(); + + footerHtml = footerHtml + .replace('{{USER_ID}}', userId) + .replace('{{CREATION_DATE}}', creationDate) + .replace('{{SCHEMA_VERSION}}', schemaVersion) + .replace('{{SCHEMA_NUMBER}}', skjemanummer) + .replace('{{userIdLabel}}', translate(TEXTS.statiske.footer.userIdLabel)) + .replace('{{createdLabel}}', translate(TEXTS.statiske.footer.createdDatelabel)) + .replace('{{schemaNumberLabel}}', translate(TEXTS.statiske.footer.schemaNumberLabel)) + .replace('{{versionLabel}}', translate(TEXTS.statiske.footer.versionLabel)) + .replace('{{pageLabel}}', translate(TEXTS.statiske.footer.pageLabel)) + .replace('{{ofLabel}}', translate(TEXTS.statiske.footer.ofLabel)); + + return footerHtml; +} diff --git a/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts b/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts index 86e02f585..e006cabf9 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/htmlBuilder.ts @@ -74,6 +74,8 @@ p {margin: 0} .innrykk {margin: 0px 0px 10px 20px;} .underskrift {margin-bottom: 30px;} .navlogored {height: 16px;float: left;margin: 4px auto 2px auto;} +@page {size: a4 portrait;margin-bottom:56px;} +section {page-break-after: always; break-after: page;} `; const body = (formSummaryObject: SummaryPanel[], confirmation?: string, signatures?: string) => ` @@ -84,7 +86,7 @@ ${confirmation || ''} ${signatures || ''} `; -const navlogo: string = `NAV logo`; +const navlogo: string = `NAV logo`; const section = (formSection: SummaryPanel) => `

${formSection.label}

diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index 855e70623..59a5ad3a1 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -9,11 +9,12 @@ import correlator from 'express-correlation-id'; import FormData from 'form-data'; import { readFileSync } from 'fs'; import path from 'path'; -import { config } from '../../../config/config'; +import { config, defaultConfig } from '../../../config/config'; import { logger } from '../../../logger'; import { appMetrics } from '../../../services'; import { synchronousResponseToError } from '../../../utils/errorHandling'; import fetchWithRetry, { HeadersInit } from '../../../utils/fetchWithRetry'; +import { generateFooterHtml } from './footerBuilder'; import { createHtmlFromSubmission } from './htmlBuilder'; export const createPdfAsByteArray = async ( @@ -39,31 +40,6 @@ export const createPdf = async ( return Buffer.from(new Uint8Array(pdf)); }; -const footer: string = - '\n' + - '\n' + - ' \n' + - '\n' + - '\n' + - '

Generert 16. Nov 2024 kl 14:30:

\n' + - '

av

\n' + - '\n' + - ''; - const filePath = path.join(process.cwd(), '/icons/nav-logo.svg'); const navIcon = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); @@ -88,7 +64,15 @@ export const createPdfFromGotenberg = async ( if (!html || Object.keys(html).length === 0) { throw Error('Missing HTML for generating PDF.'); } - //const { fodselsnummerDNummerSoker } = submission.data; + const { fodselsnummerDNummerSoker } = submission.data; + const footerHtml = await generateFooterHtml( + (fodselsnummerDNummerSoker as string | undefined) || '—', + defaultConfig.gitVersion, + form.properties.skjemanummer, + language, + translate, + ); + appMetrics.exstreamPdfRequestsCounter.inc(); let errorOccurred = false; const stopMetricRequestDuration = appMetrics.outgoingRequestDuration.startTimer({ @@ -99,7 +83,7 @@ export const createPdfFromGotenberg = async ( const options = { pdfa: true, pdfua: true }; const gotenbergUrl = config.gotenbergUrl; try { - return await createPdfCallingGotenberg(accessToken, gotenbergUrl, html, assets, options); + return await createPdfCallingGotenberg(accessToken, gotenbergUrl, html, footerHtml, assets, options); } catch (e) { errorOccurred = true; appMetrics.exstreamPdfFailuresCounter.inc(); @@ -117,6 +101,7 @@ const createPdfCallingGotenberg = async ( azureAccessToken: string, gotenbergUrl: string, html: string, + footer: string, assets: { [filename: string]: string }, options: { pdfa: boolean; pdfua: boolean }, ): Promise => { @@ -126,7 +111,7 @@ const createPdfCallingGotenberg = async ( formData.append('files', Buffer.from(html), 'index.html'); formData.append('files', Buffer.from(footer), 'footer.html'); if (navIcon != null) { - formData.append('files', Buffer.from(navIcon), 'Nav-logo.svg'); + formData.append('files', Buffer.from(navIcon), 'nav-logo.svg'); } // Add optional assets like logos, footers, etc. @@ -153,7 +138,6 @@ const createPdfCallingGotenberg = async ( if (!gotenbergResponse.ok) { const errorText = await gotenbergResponse.text(); - console.error('Gotenberg error response:', errorText); throw synchronousResponseToError( `Feil i responsdata fra Gotenberg på id "${correlator.getId()}"`, errorText, diff --git a/packages/fyllut-backend/src/routers/api/index.js b/packages/fyllut-backend/src/routers/api/index.js index 5b4f76f54..cd4e9d8ed 100644 --- a/packages/fyllut-backend/src/routers/api/index.js +++ b/packages/fyllut-backend/src/routers/api/index.js @@ -47,7 +47,7 @@ apiRouter.post('/send-inn/soknad', tokenxSendInn, sendInnSoknad.post); apiRouter.put('/send-inn/soknad', tokenxSendInn, sendInnSoknad.put); apiRouter.put('/send-inn/utfyltsoknad', azureSkjemabyggingProxy, tokenxSendInn, sendInnUtfyltSoknad.put); apiRouter.get('/common-codes/archive-subjects', kodeverkToken, commonCodes.getArchiveSubjects); -apiRouter.post('/pdf/convert', azureSkjemabyggingProxy, gotenberg.post); +apiRouter.post('/pdf/convert', gotenberg.post); apiRouter.get('/common-codes/currencies', kodeverkToken, commonCodes.getCurrencies); apiRouter.post('/log/:level', rateLimiter(60000, 60), log.post); apiRouter.get('/health/status', status.get); diff --git a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts index 98a39424c..56dc4108f 100644 --- a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts +++ b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts @@ -28,7 +28,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { it('returns 201 and location header if success', async () => { const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) - .post('/exstream') + .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const sendInnNockScope = nock(sendInnConfig.host) .put(`${sendInnConfig.paths.utfyltSoknad}/${innsendingsId}`) @@ -50,7 +50,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { it('calls next if SendInn returns error', async () => { const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) - .post('/exstream') + .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const sendInnNockScope = nock(sendInnConfig.host) .put(`${sendInnConfig.paths.utfyltSoknad}/${innsendingsId}`) @@ -72,7 +72,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { it('calls next if exstream returns error', async () => { const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) - .post('/exstream') + .post('/gotenberg') .reply(500, 'error body'); const req = mockRequestWithPidAndTokenX({ body: defaultBody }); const res = mockResponse(); diff --git a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts index 6c075a84d..e7dca33cf 100644 --- a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts +++ b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.ts @@ -33,7 +33,7 @@ const sendInnUtfyltSoknad = { next(new Error(errorMessage)); return; } - logger.warning('***** Skal konvertere søknad til PDF ******'); + const pdfByteArray = await createPdfAsByteArray( req.headers.AzureAccessToken as string, form, diff --git a/packages/shared-domain/src/texts/statiskeTekster.js b/packages/shared-domain/src/texts/statiskeTekster.js index 0ea0cd0d7..66642dbaf 100644 --- a/packages/shared-domain/src/texts/statiskeTekster.js +++ b/packages/shared-domain/src/texts/statiskeTekster.js @@ -216,4 +216,12 @@ export const statiske = { identityNumber: 'Fødselsnummer eller d-nummer', yourBirthdate: 'Fødselsdato (dd.mm.åååå)', }, + footer: { + userIdLabel: 'F.nr', + createdDatelabel: 'Opprettet', + schemaNumberLabel: 'Skjemanummer', + versionLabel: 'Versjon', + pageLabel: 'Side', + ofLabel: 'av', + }, }; From 53a4f9ee8ea3f86f7e925d794a61555a62fc4c95 Mon Sep 17 00:00:00 2001 From: nilsarne Date: Mon, 6 Jan 2025 14:00:56 +0100 Subject: [PATCH 3/8] Endringer etter PR --- packages/fyllut-backend/.env.test | 1 + .../routers/api/helpers/footerBuilder.test.ts | 28 +++++++++++++++++++ .../src/routers/api/helpers/footerBuilder.ts | 8 +----- .../src/routers/api/helpers/pdfService.ts | 17 +++++++++-- packages/fyllut-backend/src/test/test.env | 1 + packages/fyllut/cypress.config.ts | 1 + 6 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 packages/fyllut-backend/src/routers/api/helpers/footerBuilder.test.ts diff --git a/packages/fyllut-backend/.env.test b/packages/fyllut-backend/.env.test index 16633a84e..8773b3ea2 100644 --- a/packages/fyllut-backend/.env.test +++ b/packages/fyllut-backend/.env.test @@ -13,3 +13,4 @@ TOKEN_X_WELL_KNOWN_URL=http://127.0.0.1:3300/tokenx/.well-known AMPLITUDE_API_ENDPOINT=http://127.0.0.1:3300/amplitude/collect-auto AMPLITUDE_DISABLE_BATCH=true # FYLLUT_BACKEND_LOGLEVEL=debug +GOTENBERG_URL=http://127.0.0.1:3000 diff --git a/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.test.ts b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.test.ts new file mode 100644 index 000000000..85fef9787 --- /dev/null +++ b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.test.ts @@ -0,0 +1,28 @@ +import { generateFooterHtml } from './footerBuilder'; + +const mockTranslate = (text: string) => text; + +describe('footerBuilder', () => { + describe('createFooter', () => { + const userId: string = '12345678901'; + const schemaVersion: string = '342u43590534mklgfd0i9'; + const skjemanummer: string = 'NAV 11-12.24B'; + const language: string = 'nb'; + + let footer: string; + + it('creates a footer html document with labels and the supplied data', () => { + footer = generateFooterHtml(userId, schemaVersion, skjemanummer, language, mockTranslate); + expect(footer).toContain(userId); + expect(footer).toContain(schemaVersion); + expect(footer).toContain(skjemanummer); + expect(footer).toContain('F.nr: ' + userId + ''); + expect(footer).toContain('Opprettet: '); + expect(footer).toContain('Skjemanummer: ' + skjemanummer + ''); + expect(footer).toContain('Versjon: ' + schemaVersion + ''); + expect(footer).toContain( + 'Side av ', + ); + }); + }); +}); diff --git a/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts index a3854ee36..32477c84a 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/footerBuilder.ts @@ -4,13 +4,7 @@ import path from 'path'; const filePath = path.join(process.cwd(), '/src/routers/api/helpers/footer-template.html'); -export async function generateFooterHtml( - userId, - schemaVersion, - skjemanummer, - language, - translate: (text: string) => string, -) { +export function generateFooterHtml(userId, schemaVersion, skjemanummer, language, translate: (text: string) => string) { let footerHtml = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); const creationDate = new Date().toLocaleString(); diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index 59a5ad3a1..e32121be8 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -13,7 +13,8 @@ import { config, defaultConfig } from '../../../config/config'; import { logger } from '../../../logger'; import { appMetrics } from '../../../services'; import { synchronousResponseToError } from '../../../utils/errorHandling'; -import fetchWithRetry, { HeadersInit } from '../../../utils/fetchWithRetry'; +//import fetchWithRetry, { HeadersInit } from '../../../utils/fetchWithRetry'; +import fetch from 'node-fetch'; import { generateFooterHtml } from './footerBuilder'; import { createHtmlFromSubmission } from './htmlBuilder'; @@ -65,7 +66,7 @@ export const createPdfFromGotenberg = async ( throw Error('Missing HTML for generating PDF.'); } const { fodselsnummerDNummerSoker } = submission.data; - const footerHtml = await generateFooterHtml( + const footerHtml = generateFooterHtml( (fodselsnummerDNummerSoker as string | undefined) || '—', defaultConfig.gitVersion, form.properties.skjemanummer, @@ -125,6 +126,7 @@ const createPdfCallingGotenberg = async ( formData.append('skipNetworkIdleEvent', 'false'); // Send the request to Gotenberg + /* const gotenbergResponse = await fetchWithRetry(`${gotenbergUrl}/forms/chromium/convert/html`, { retry: 3, headers: { @@ -135,6 +137,17 @@ const createPdfCallingGotenberg = async ( method: 'POST', body: formData, }); +*/ + + const gotenbergResponse = await fetch(`${gotenbergUrl}/forms/chromium/convert/html`, { + method: 'POST', + headers: { + ...formData.getHeaders(), + //Authorization: `Bearer ${azureAccessToken}`, + 'x-correlation-id': correlator.getId(), + } as HeadersInit, + body: formData, + }); if (!gotenbergResponse.ok) { const errorText = await gotenbergResponse.text(); diff --git a/packages/fyllut-backend/src/test/test.env b/packages/fyllut-backend/src/test/test.env index 44b4e3f1c..69378a4d4 100644 --- a/packages/fyllut-backend/src/test/test.env +++ b/packages/fyllut-backend/src/test/test.env @@ -12,6 +12,7 @@ SEND_INN_HOST=https://innsending-api.unittest.nav.no NORG2_URL=https://norg2.unittest.nav.no SEND_INN_TOKEN_X_CLIENT_ID=test-gcp:soknad:send-inn FORMS_API_URL=https://forms-api-test.nav.no +GOTENBERG_URL=http://127.0.0.1:3000 # FYLLUT_BACKEND_LOGLEVEL=debug diff --git a/packages/fyllut/cypress.config.ts b/packages/fyllut/cypress.config.ts index fcf2d3707..2f85d7ad1 100644 --- a/packages/fyllut/cypress.config.ts +++ b/packages/fyllut/cypress.config.ts @@ -15,6 +15,7 @@ export default defineConfig({ TOKEN_X_WELL_KNOWN_URL: 'http://127.0.0.1:3300/tokenx/.well-known', AMPLITUDE_API_ENDPOINT: 'http://127.0.0.1:3300/amplitude/collect-auto', BASE_URL: 'http://localhost:3001', + GOTENBERG_URL: 'http://127.0.0.1:3000', }, }, }); From 1cc5d45fda3a84c3df3d36df854ec1c2006f2e61 Mon Sep 17 00:00:00 2001 From: nilsarne Date: Tue, 7 Jan 2025 12:10:54 +0100 Subject: [PATCH 4/8] Endringer etter PR. Fikse feil env parametere --- packages/fyllut-backend/src/app.test.ts | 7 +------ .../src/routers/api/send-inn-utfylt-soknad.test.ts | 8 +++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/fyllut-backend/src/app.test.ts b/packages/fyllut-backend/src/app.test.ts index 5717484e3..005377199 100644 --- a/packages/fyllut-backend/src/app.test.ts +++ b/packages/fyllut-backend/src/app.test.ts @@ -232,7 +232,6 @@ describe('app', () => { const innsendingsId = '65ed0008-ec72-4c90-8b44-165d3c265da0'; const sendInnLocation = 'http://www.unittest.nav.no/sendInn/123'; - const azureTokenEndpoint = process.env.AZURE_OPENID_CONFIG_TOKEN_ENDPOINT!; const tokenxEndpoint = 'http://tokenx-unittest.nav.no/token'; const applicationData = { form: { @@ -249,10 +248,7 @@ describe('app', () => { innsendingsId, }; - const azureOpenidScope = nock(extractHost(azureTokenEndpoint)) - .post(extractPath(azureTokenEndpoint)) - .reply(200, { access_token: 'azure-access-token' }); - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL as string) + const skjemabyggingproxyScope = nock(process.env.GOTENBERG_URL as string) .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const tokenxWellKnownScope = nock(extractHost(tokenxConfig?.wellKnownUrl)) @@ -273,7 +269,6 @@ describe('app', () => { expect(res.status).toBe(201); expect(res.headers['location']).toMatch(sendInnLocation); - azureOpenidScope.done(); skjemabyggingproxyScope.done(); tokenxWellKnownScope.done(); tokenEndpointNockScope.done(); diff --git a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts index 56dc4108f..fbd7df7eb 100644 --- a/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts +++ b/packages/fyllut-backend/src/routers/api/send-inn-utfylt-soknad.test.ts @@ -27,7 +27,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { }; it('returns 201 and location header if success', async () => { - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) + const skjemabyggingproxyScope = nock(process.env.GOTENBERG_URL!) .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const sendInnNockScope = nock(sendInnConfig.host) @@ -49,7 +49,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { }); it('calls next if SendInn returns error', async () => { - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) + const skjemabyggingproxyScope = nock(process.env.GOTENBERG_URL!) .post('/gotenberg') .reply(200, { data: { result: [{ content: { data: '' } }] } }); const sendInnNockScope = nock(sendInnConfig.host) @@ -71,9 +71,7 @@ describe('[endpoint] send-inn/utfyltsoknad', () => { }); it('calls next if exstream returns error', async () => { - const skjemabyggingproxyScope = nock(process.env.SKJEMABYGGING_PROXY_URL!) - .post('/gotenberg') - .reply(500, 'error body'); + const skjemabyggingproxyScope = nock(process.env.GOTENBERG_URL!).post('/gotenberg').reply(500, 'error body'); const req = mockRequestWithPidAndTokenX({ body: defaultBody }); const res = mockResponse(); const next = vi.fn(); From 2c56a3ead619130e2935992817691f0a3de3db9f Mon Sep 17 00:00:00 2001 From: nilsarne Date: Tue, 7 Jan 2025 13:00:53 +0100 Subject: [PATCH 5/8] Endringer etter PR. Fikse feil endring sti til nav-logo.svg --- packages/fyllut-backend/src/routers/api/helpers/pdfService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index e32121be8..e2cdb2e27 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -41,7 +41,7 @@ export const createPdf = async ( return Buffer.from(new Uint8Array(pdf)); }; -const filePath = path.join(process.cwd(), '/icons/nav-logo.svg'); +const filePath = path.join(process.cwd(), '', '/icons/nav-logo.svg'); const navIcon = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); From 0508cbb9530e3da499f7ee2c4a3093e9549baf20 Mon Sep 17 00:00:00 2001 From: nilsarne Date: Mon, 20 Jan 2025 21:17:46 +0100 Subject: [PATCH 6/8] Test endringer --- .../src/routers/api/gotenberg.ts | 2 +- .../src/routers/api/helpers/pdfService.ts | 51 ++++++++++--------- packages/fyllut-backend/src/test/test.env | 1 + .../fyllut-backend/src/test/testHelpers.ts | 1 + packages/fyllut-backend/tsconfig.json | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/fyllut-backend/src/routers/api/gotenberg.ts b/packages/fyllut-backend/src/routers/api/gotenberg.ts index 81c6d7bf1..2cf0a6027 100644 --- a/packages/fyllut-backend/src/routers/api/gotenberg.ts +++ b/packages/fyllut-backend/src/routers/api/gotenberg.ts @@ -43,7 +43,7 @@ const gotenberg = { ); res.setHeader('Content-Type', 'application/pdf'); - res.status(200).send(Buffer.from(new Uint8Array(pdf))); + res.send(Buffer.from(new Uint8Array(pdf))); } catch (e) { logErrorWithStacktrace(e as Error); const createPdfError = htmlResponseError('Generering av PDF feilet'); diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index e2cdb2e27..f7304157f 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -125,8 +125,9 @@ const createPdfCallingGotenberg = async ( formData.append('pdfua', options.pdfua ? 'true' : ''); formData.append('skipNetworkIdleEvent', 'false'); - // Send the request to Gotenberg - /* + try { + // Send the request to Gotenberg + /* const gotenbergResponse = await fetchWithRetry(`${gotenbergUrl}/forms/chromium/convert/html`, { retry: 3, headers: { @@ -138,28 +139,32 @@ const createPdfCallingGotenberg = async ( body: formData, }); */ + //, 'content-type': 'multipart/form-data' + const gotenbergResponse = await fetch(`${gotenbergUrl}/forms/chromium/convert/html`, { + method: 'POST', + headers: { + ...formData.getHeaders(), + //'x-correlation-id': correlator.getId(), + accept: 'application/pdf, application/text', + } as HeadersInit, + body: formData, + }); - const gotenbergResponse = await fetch(`${gotenbergUrl}/forms/chromium/convert/html`, { - method: 'POST', - headers: { - ...formData.getHeaders(), - //Authorization: `Bearer ${azureAccessToken}`, - 'x-correlation-id': correlator.getId(), - } as HeadersInit, - body: formData, - }); + if (!gotenbergResponse.ok) { + const errorText = await gotenbergResponse.text(); + throw synchronousResponseToError( + `Feil i responsdata fra Gotenberg på id "${correlator.getId()}"`, + errorText, + gotenbergResponse.status, + gotenbergResponse.url, + true, + ); + } - if (!gotenbergResponse.ok) { - const errorText = await gotenbergResponse.text(); - throw synchronousResponseToError( - `Feil i responsdata fra Gotenberg på id "${correlator.getId()}"`, - errorText, - gotenbergResponse.status, - gotenbergResponse.url, - true, - ); + const pdfBuffer = gotenbergResponse.arrayBuffer(); + return pdfBuffer; + } catch (e) { + logger.error(`Request to gotenberg pdf service failed with ${e}`); + throw e; } - - const pdfBuffer = gotenbergResponse.arrayBuffer(); - return pdfBuffer; }; diff --git a/packages/fyllut-backend/src/test/test.env b/packages/fyllut-backend/src/test/test.env index 69378a4d4..1c6b6f67a 100644 --- a/packages/fyllut-backend/src/test/test.env +++ b/packages/fyllut-backend/src/test/test.env @@ -12,6 +12,7 @@ SEND_INN_HOST=https://innsending-api.unittest.nav.no NORG2_URL=https://norg2.unittest.nav.no SEND_INN_TOKEN_X_CLIENT_ID=test-gcp:soknad:send-inn FORMS_API_URL=https://forms-api-test.nav.no +#GOTENBERG_URL=https://convert-to-pdf.intern.dev.nav.no GOTENBERG_URL=http://127.0.0.1:3000 # FYLLUT_BACKEND_LOGLEVEL=debug diff --git a/packages/fyllut-backend/src/test/testHelpers.ts b/packages/fyllut-backend/src/test/testHelpers.ts index 5c06893ab..e31a04a80 100644 --- a/packages/fyllut-backend/src/test/testHelpers.ts +++ b/packages/fyllut-backend/src/test/testHelpers.ts @@ -34,6 +34,7 @@ function mockResponse(): MockedResponse { contentType: vi.fn(), status: vi.fn(), sendStatus: vi.fn(), + setHeader: vi.fn(), header: vi.fn(), } as unknown as MockedResponse; } diff --git a/packages/fyllut-backend/tsconfig.json b/packages/fyllut-backend/tsconfig.json index cb7c847ad..a84d9614b 100644 --- a/packages/fyllut-backend/tsconfig.json +++ b/packages/fyllut-backend/tsconfig.json @@ -6,5 +6,5 @@ "@navikt/skjemadigitalisering-shared-domain": ["../shared-domain/src"] } }, - "include": ["src"] + "include": ["src", "icons"] } From d656e64f2ea434cfd0d0e5e7fa0ecf27c4529b55 Mon Sep 17 00:00:00 2001 From: nilsarne Date: Thu, 23 Jan 2025 12:01:39 +0100 Subject: [PATCH 7/8] Test endringer --- packages/bygger/package.json | 3 +- packages/fyllut-backend/src/app.test.ts | 9 ++- .../src/routers/api/helpers/pdfService.ts | 36 +++++---- packages/fyllut-backend/src/test/test.env | 2 +- packages/fyllut-backend/tsconfig.json | 4 +- packages/fyllut-backend/vite.config.ts | 9 +++ yarn.lock | 74 ++++++++++++++++++- 7 files changed, 110 insertions(+), 27 deletions(-) diff --git a/packages/bygger/package.json b/packages/bygger/package.json index dbf065a55..44ba2a4ec 100644 --- a/packages/bygger/package.json +++ b/packages/bygger/package.json @@ -44,6 +44,7 @@ }, "devDependencies": { "@testing-library/react": "^16.0.1", - "lodash.template": "^4.5.0" + "lodash.template": "^4.5.0", + "vite-plugin-static-copy": "^2.2.0" } } diff --git a/packages/fyllut-backend/src/app.test.ts b/packages/fyllut-backend/src/app.test.ts index 005377199..f3e54a768 100644 --- a/packages/fyllut-backend/src/app.test.ts +++ b/packages/fyllut-backend/src/app.test.ts @@ -224,7 +224,7 @@ describe('app', () => { skjemabyggingproxyScope.done(); }); - it('Performs TokenX exchange and retrieves pdf from exstream before calling SendInn', async () => { + it('Performs TokenX exchange and retrieves pdf from Gotenberg before calling SendInn', async () => { const key = await generateJwk(); nock('https://testoidc.unittest.no') .get('/idporten-oidc-provider/jwk') @@ -247,10 +247,11 @@ describe('app', () => { submissionMethod: 'digital', innsendingsId, }; - + const mockSuccessResponse = new Uint8Array([37, 80, 68, 70, 45]); + console.log(process.env.GOTENBERG_URL as string); const skjemabyggingproxyScope = nock(process.env.GOTENBERG_URL as string) - .post('/gotenberg') - .reply(200, { data: { result: [{ content: { data: '' } }] } }); + .post('/forms/chromium/convert/html') + .reply(200, mockSuccessResponse); const tokenxWellKnownScope = nock(extractHost(tokenxConfig?.wellKnownUrl)) .get(extractPath(tokenxConfig?.wellKnownUrl)) .reply(200, { token_endpoint: tokenxEndpoint }); diff --git a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts index f7304157f..656d9c776 100644 --- a/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts +++ b/packages/fyllut-backend/src/routers/api/helpers/pdfService.ts @@ -13,8 +13,8 @@ import { config, defaultConfig } from '../../../config/config'; import { logger } from '../../../logger'; import { appMetrics } from '../../../services'; import { synchronousResponseToError } from '../../../utils/errorHandling'; -//import fetchWithRetry, { HeadersInit } from '../../../utils/fetchWithRetry'; -import fetch from 'node-fetch'; +//import fetch from 'node-fetch'; +import fetchWithRetry from '../../../utils/fetchWithRetry'; import { generateFooterHtml } from './footerBuilder'; import { createHtmlFromSubmission } from './htmlBuilder'; @@ -42,6 +42,7 @@ export const createPdf = async ( }; const filePath = path.join(process.cwd(), '', '/icons/nav-logo.svg'); +//const filePath = '../../../../public/icons/nav-logo.svg'; const navIcon = readFileSync(filePath, { encoding: 'utf-8', flag: 'r' }); @@ -125,30 +126,33 @@ const createPdfCallingGotenberg = async ( formData.append('pdfua', options.pdfua ? 'true' : ''); formData.append('skipNetworkIdleEvent', 'false'); + console.log(`${gotenbergUrl}/forms/chromium/convert/html`); + try { // Send the request to Gotenberg + const gotenbergResponse = await fetchWithRetry(`${gotenbergUrl}/forms/chromium/convert/html`, { + retry: 3, + headers: { + ...formData.getHeaders(), + //Authorization: `Bearer ${azureAccessToken}`, + contentType: 'multipart/form-data', + accept: 'application/pdf, text/plain', + } as HeadersInit, + method: 'POST', + body: formData, + }); + /* - const gotenbergResponse = await fetchWithRetry(`${gotenbergUrl}/forms/chromium/convert/html`, { - retry: 3, - headers: { - ...formData.getHeaders(), - //Authorization: `Bearer ${azureAccessToken}`, - 'x-correlation-id': correlator.getId(), - } as HeadersInit, - method: 'POST', - body: formData, - }); -*/ - //, 'content-type': 'multipart/form-data' const gotenbergResponse = await fetch(`${gotenbergUrl}/forms/chromium/convert/html`, { method: 'POST', headers: { ...formData.getHeaders(), - //'x-correlation-id': correlator.getId(), - accept: 'application/pdf, application/text', + contentType: 'multipart/form-data', + accept: 'application/pdf, text/plain', } as HeadersInit, body: formData, }); +*/ if (!gotenbergResponse.ok) { const errorText = await gotenbergResponse.text(); diff --git a/packages/fyllut-backend/src/test/test.env b/packages/fyllut-backend/src/test/test.env index 1c6b6f67a..4d2569eea 100644 --- a/packages/fyllut-backend/src/test/test.env +++ b/packages/fyllut-backend/src/test/test.env @@ -13,7 +13,7 @@ NORG2_URL=https://norg2.unittest.nav.no SEND_INN_TOKEN_X_CLIENT_ID=test-gcp:soknad:send-inn FORMS_API_URL=https://forms-api-test.nav.no #GOTENBERG_URL=https://convert-to-pdf.intern.dev.nav.no -GOTENBERG_URL=http://127.0.0.1:3000 +GOTENBERG_URL=http://www.gotenberg.no # FYLLUT_BACKEND_LOGLEVEL=debug diff --git a/packages/fyllut-backend/tsconfig.json b/packages/fyllut-backend/tsconfig.json index a84d9614b..9c580fbaf 100644 --- a/packages/fyllut-backend/tsconfig.json +++ b/packages/fyllut-backend/tsconfig.json @@ -6,5 +6,7 @@ "@navikt/skjemadigitalisering-shared-domain": ["../shared-domain/src"] } }, - "include": ["src", "icons"] + "include": ["src", + "icons" + ] } diff --git a/packages/fyllut-backend/vite.config.ts b/packages/fyllut-backend/vite.config.ts index ae657859c..df1b16e56 100644 --- a/packages/fyllut-backend/vite.config.ts +++ b/packages/fyllut-backend/vite.config.ts @@ -1,6 +1,7 @@ /// import { defineConfig, PluginOption } from 'vite'; import { VitePluginNode } from 'vite-plugin-node'; +import { viteStaticCopy } from 'vite-plugin-static-copy'; import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig(({ mode }) => { @@ -9,6 +10,14 @@ export default defineConfig(({ mode }) => { adapter: 'express', appPath: './src/server.js', }), + viteStaticCopy({ + targets: [ + { + src: './icons/nav-logo.svg', // src folder + dest: './icons/nav-logo.svg', // Destination folder in `dist` + }, + ], + }), ]; if (mode !== 'production') { diff --git a/yarn.lock b/yarn.lock index 97c4ef2ae..61d19a574 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2109,6 +2109,14 @@ ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + arch@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz" @@ -2400,6 +2408,11 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + bintrees@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz" @@ -2453,7 +2466,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.3: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -2630,6 +2643,21 @@ check-more-types@^2.24.0: resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz" integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + ci-info@^3.2.0: version "3.8.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" @@ -4623,6 +4651,15 @@ fs-extra@^10.0.1: jsonfile "^6.0.1" universalify "^2.0.0" +fs-extra@^11.1.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" + integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" @@ -4757,7 +4794,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -5255,6 +5292,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" @@ -5332,7 +5376,7 @@ is-generator-function@^1.0.10: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -6547,6 +6591,11 @@ node-releases@^2.0.18: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" @@ -6895,7 +6944,7 @@ picocolors@^1.1.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== -picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -7339,6 +7388,13 @@ readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + redent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" @@ -8688,6 +8744,16 @@ vite-plugin-node@^3.1.0: chalk "^4.1.2" debug "^4.3.2" +vite-plugin-static-copy@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vite-plugin-static-copy/-/vite-plugin-static-copy-2.2.0.tgz#8eec750f016e508b09234da880e9310cd1367b9b" + integrity sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w== + dependencies: + chokidar "^3.5.3" + fast-glob "^3.2.11" + fs-extra "^11.1.0" + picocolors "^1.0.0" + vite-tsconfig-paths@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-5.0.1.tgz#c9387a29c32fd586e4c7f4e2b2da1f0b5c9a7403" From 734f3a4c728e42916d2d049bd9cbbbd74a7451ed Mon Sep 17 00:00:00 2001 From: nilsarne Date: Thu, 23 Jan 2025 12:14:45 +0100 Subject: [PATCH 8/8] Test endringer --- .../src/routers/api/gotenberg.test.ts | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 packages/fyllut-backend/src/routers/api/gotenberg.test.ts diff --git a/packages/fyllut-backend/src/routers/api/gotenberg.test.ts b/packages/fyllut-backend/src/routers/api/gotenberg.test.ts new file mode 100644 index 000000000..738e26833 --- /dev/null +++ b/packages/fyllut-backend/src/routers/api/gotenberg.test.ts @@ -0,0 +1,99 @@ +import nock from 'nock'; +import { config } from '../../config/config'; +import { mockRequest, mockResponse } from '../../test/testHelpers'; +import gotenberg from './gotenberg'; + +const formTitle = 'testskjema'; +const defaultBody = { + form: JSON.stringify({ title: formTitle, components: [], properties: { skjemanummer: 'NAV 12.34-56' } }), + submission: JSON.stringify({ data: {} }), + submissionMethod: 'paper', + translations: JSON.stringify({}), + language: 'nb-NO', +}; +const mockSuccessResponse = new Uint8Array([37, 80, 68, 70, 45]); // A minimal valid PDF file header + +describe('gotenberg', () => { + afterEach(() => { + expect(nock.isDone()).toBe(true); + }); + + it('decodes and sends the pdf on success', async () => { + //TEST + /* + const { skjemabyggingProxyUrl } = config; + const generateFileMock = nock(skjemabyggingProxyUrl!).post('/foersteside').reply(200, {}); + const req1 = mockRequest({ + headers: { + AzureAccessToken: '', + 'Accept': 'application/pdf, text/plain' + }, + body: { + foerstesidetype: 'ETTERSENDELSE', + navSkjemaId: 'NAV 10.10.10', + spraakkode: 'NB', + overskriftstittel: 'Tittel', + arkivtittel: 'Tittel', + tema: 'HJE', + }, + }); + + await forsteside.post(req1, mockResponse(), mockNext()); + + expect(generateFileMock.isDone()).toBe(true); +*/ + + //, 'Content-Disposition': 'attachment; filename=\"index.html\"' + // , { 'accept': 'application/pdf, text/plain', 'content-type': 'multipart/form-data'} + const url = config.gotenbergUrl; + console.log(`${url}/forms/chromium/convert/html`); + const gotenbergScope = nock(url!).post('/forms/chromium/convert/html').reply(200, mockSuccessResponse); + + /* + const gotenbergScope = nock(url) + .post('/forms/chromium/convert/html') + .reply(200, 'mockSuccessResponse') + ; +*/ + nock.recorder.rec(); + console.log(gotenbergScope.activeMocks()); + /* + //TEST + try { + const response = await fetch(`${url}/forms/chromium/convert/html`, { + method: 'POST', + //body: JSON.stringify({data: 'test'}), + //headers: { 'Accept': 'application/pdf, text/plain', 'Content-Type': 'multipart/form-data' }, + }); + console.log(response.status); + } catch (e) { + console.error(e); + } +*/ + + const req = mockRequest({ headers: {}, body: defaultBody }); + const res = mockResponse(); + const next = vi.fn(); + await gotenberg.post(req, res, next); + expect(next).not.toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledTimes(1); + expect(res.send).toHaveReturned(); + gotenbergScope.done(); + }); + + it('calls next if skjemabygging-proxy returns error', async () => { + const url = config.gotenbergUrl; + const gotenbergScope = nock(url).post('/forms/chromium/convert/html').reply(500, 'error body'); + const req = mockRequest({ headers: {}, body: defaultBody }); + const res = mockResponse(); + const next = vi.fn(); + await gotenberg.post(req, res, next); + + //expect(next).toHaveBeenCalledTimes(1); + const error = next.mock.calls[0][0]; + expect(error?.message).toBe('Generering av PDF feilet'); + expect(error?.render_html).toBe(true); + expect(res.send).not.toHaveBeenCalled(); + gotenbergScope.done(); + }); +});