Skip to content

Commit 00641cc

Browse files
authored
Merge pull request #1427 from navikt/feat/forms-api-forms
Feat/forms api forms
2 parents 73418da + 46e479c commit 00641cc

File tree

263 files changed

+11443
-7641
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

263 files changed

+11443
-7641
lines changed

.github/workflows/cypress-tests.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ jobs:
1818
node-version: '20.9.0'
1919
registry-url: https://npm.pkg.github.com/
2020
scope: '@navikt'
21+
- name: set timezone
22+
uses: szenius/[email protected]
23+
with:
24+
timezoneLinux: 'Europe/Oslo'
2125
- name: 'Install dependencies'
2226
run: yarn --frozen-lockfile
2327
- name: 'Build application'
@@ -56,6 +60,10 @@ jobs:
5660
node-version: '20.9.0'
5761
registry-url: https://npm.pkg.github.com/
5862
scope: '@navikt'
63+
- name: set timezone
64+
uses: szenius/[email protected]
65+
with:
66+
timezoneLinux: 'Europe/Oslo'
5967
- name: 'Install dependencies'
6068
run: yarn --frozen-lockfile
6169
- name: 'Build application'
@@ -70,3 +78,9 @@ jobs:
7078
command: yarn cypress:bygger
7179
config: video=false
7280
config-file: cypress.config.ts
81+
- name: Upload screenshots
82+
uses: actions/upload-artifact@v4
83+
if: failure()
84+
with:
85+
name: cypress-bygger-screenshots
86+
path: ${{ github.workspace }}/packages/bygger/cypress/screenshots/*

.nais/bygger/preprod-alt.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ environmentVars:
3535
value: http://formio-enterprise-server
3636
- name: FORMIO_PROJECT_NAME_PROD
3737
value: jvcemxwcpghcqjn
38+
- name: FORMS_API_URL_PROD
39+
value: https://forms-api.nav.no
3840
azure:
3941
ad_groups:
4042
- id: b7012a89-90b9-4215-b7dc-988b929216e9

.nais/bygger/preprod.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ environmentVars:
3838
value: http://formio-enterprise-server
3939
- name: FORMIO_PROJECT_NAME_PROD
4040
value: jvcemxwcpghcqjn
41+
- name: FORMS_API_URL_PROD
42+
value: https://forms-api.nav.no
4143
azure:
4244
ad_groups:
4345
- id: b7012a89-90b9-4215-b7dc-988b929216e9

.nais/fyllut/dev-delingslenke.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ forms-api-url: https://forms-api.nav.no
1414
kodeverk:
1515
url: https://kodeverk-api.nav.no
1616
scope: dev-gcp.team-rocket.kodeverk-api
17-
forms-source: "formioapi"
17+
forms-source: "formsapi-staging"
1818
pdl-token-scope-cluster: "dev-fss"
1919
azure:
2020
application:

.nais/fyllut/preprod-alt.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ send-inn-host: http://innsending-api.team-soknad
1414
kodeverk:
1515
url: https://kodeverk-api.nav.no
1616
scope: dev-gcp.team-rocket.kodeverk-api
17-
forms-source: "formioapi"
17+
forms-source: "formsapi-staging"
1818
environmentVars:
1919
- name: FORMIO_API_SERVICE
2020
value: http://formio-api

.nais/fyllut/preprod.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ send-inn-host: http://innsending-api.team-soknad
1414
kodeverk:
1515
url: https://kodeverk-api.nav.no
1616
scope: dev-gcp.team-rocket.kodeverk-api
17-
forms-source: "formioapi"
17+
forms-source: "formsapi-staging"
1818
environmentVars:
1919
- name: FORMIO_API_SERVICE
2020
value: http://formio-api

README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,7 @@ Docker-image bygges og startes lokalt på følgende måte:
216216
# image: fyllut-base
217217
docker build --tag fyllut-base -f ./docker/Dockerfile.fyllut-base --build-arg git_sha=local ./packages
218218
docker run \
219-
-e FORMS_SOURCE=formioapi \
220-
-e FORMIO_API_SERVICE=https://formio-api.intern.dev.nav.no \
221-
-e FORMIO_PROJECT_NAME=jvcemxwcpghcqjn \
219+
-e FORMS_SOURCE=formsapi-staging \
222220
-e FORMS_API_URL=https://forms-api.intern.dev.nav.no \
223221
-e NAIS_CLUSTER_NAME=dev-gcp \
224222
-p 8080:8080 fyllut-base

mocks/mocks/collections.json

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
"get-active-tasks:success",
1414
"put-soknad:success",
1515
"get-soknad:success-1",
16-
"get-soknad:success-mellomlagring-nested-norwegian-business",
17-
"get-soknad:success-mellomlagring-nested-foreign-business",
1816
"delete-soknad:success",
1917
"put-utfylt-soknad:success",
2018
"send-inn-frontend:available",

mocks/mocks/data/formio-api/attachments.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@
2727
"required": true
2828
},
2929
"attachmentValues": {
30-
"leggerVedNaa": {
30+
"nei": {
3131
"enabled": true,
3232
"additionalDocumentation": {
33-
"enabled": true,
34-
"label": "Ledetekst tilleggsinformasjon",
35-
"description": "Beskrivelse av krav til tilleggsinformasjon"
33+
"enabled": false
3634
}
3735
},
3836
"ettersender": {
@@ -42,10 +40,12 @@
4240
"enabled": false
4341
}
4442
},
45-
"nei": {
43+
"leggerVedNaa": {
4644
"enabled": true,
4745
"additionalDocumentation": {
48-
"enabled": false
46+
"enabled": true,
47+
"label": "Ledetekst tilleggsinformasjon",
48+
"description": "Beskrivelse av krav til tilleggsinformasjon"
4949
}
5050
}
5151
},

packages/bygger-backend/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@types/uuid": "^10.0.0",
5050
"memorystream": "^0.3.1",
5151
"nock": "^13.5.6",
52-
"vite-plugin-node": "^4.0.0"
52+
"vite-plugin-node": "^4.0.0",
53+
"vitest-mock-extended": "^2.0.2"
5354
}
5455
}

packages/bygger-backend/src/GitHubRepo.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ export class GitHubRepo {
5050
log: {
5151
debug: () => {},
5252
info: () => {},
53-
warn: logger.warn,
54-
error: logger.error,
53+
warn: logger.warn.bind(logger),
54+
error: logger.error.bind(logger),
5555
},
5656
});
5757
}

packages/bygger-backend/src/config/development.ts

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ export const devFormsApi: FormsApiConfig = {
4747
},
4848
};
4949

50+
export const prodFormsApi: Pick<FormsApiConfig, 'url'> = {
51+
url: 'https://forms-api.nav.no',
52+
};
53+
5054
export const devPusher: Partial<PusherConfig> = {
5155
cluster: 'eu',
5256
};

packages/bygger-backend/src/config/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
devPusher,
1212
devSkjemabyggingProxy,
1313
prodFormio,
14+
prodFormsApi,
1415
} from './development';
1516
import { ConfigType, NodeEnv } from './types';
1617

@@ -99,6 +100,12 @@ const config: ConfigType = {
99100
},
100101
devToken: isDevelopment ? optionalEnv('FORMS_API_ACCESS_TOKEN') : undefined,
101102
},
103+
prodFormsApi:
104+
naisClusterName !== 'prod-gcp'
105+
? {
106+
url: env('FORMS_API_URL_PROD', prodFormsApi.url),
107+
}
108+
: undefined,
102109
pusher: {
103110
cluster: env('PUSHER_CLUSTER', devPusher.cluster),
104111
key: env('PUSHER_KEY'),

packages/bygger-backend/src/config/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export type ConfigType = {
6868
prodFormio?: Pick<FormioConfig, 'apiService' | 'projectName'>;
6969
fyllut: FyllutConfig;
7070
formsApi: FormsApiConfig;
71+
prodFormsApi?: Pick<FormsApiConfig, 'url'>;
7172
pusher: PusherConfig;
7273
githubApp: GithubAppConfig;
7374
gitSha: string;

packages/bygger-backend/src/fetchUtils.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,18 @@ export async function fetchWithErrorHandling(url: RequestInfo, options: RequestI
4343
data: null,
4444
};
4545
}
46+
if (res.headers.get('content-type')?.includes('application/json')) {
47+
return {
48+
status: 'OK',
49+
data: await res.json(),
50+
};
51+
}
52+
53+
const logMeta = { status: res.status, method };
54+
logger.warn(`Fetch ${method} ${url}: Unexpected content-type "${res.headers.get('content-type')}"`, logMeta);
4655
return {
4756
status: 'OK',
48-
data: await res.json(),
57+
data: null,
4958
};
5059
}
5160

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { formioFormsApiUtils, TranslationLang } from '@navikt/skjemadigitalisering-shared-domain';
2+
import { RequestHandler } from 'express';
3+
import { formPublicationsService, formsService } from '../../../services';
4+
import { mapLanguageCodeToFormioFormat } from './utils';
5+
6+
const getAll: RequestHandler = async (req, res, next) => {
7+
try {
8+
const allPublishedForms = await formPublicationsService.getAll();
9+
res.json(allPublishedForms);
10+
} catch (error) {
11+
next(error);
12+
}
13+
};
14+
15+
const get: RequestHandler = async (req, res, next) => {
16+
const { formPath } = req.params;
17+
try {
18+
const form = await formPublicationsService.get(formPath);
19+
res.json(form);
20+
} catch (error) {
21+
next(error);
22+
}
23+
};
24+
25+
const post: RequestHandler = async (req, res, next) => {
26+
const { formPath } = req.params;
27+
const { languageCodes, revision } = req.query; // TODO
28+
const accessToken = req.headers.AzureAccessToken as string;
29+
30+
try {
31+
const form = await formPublicationsService.post(
32+
formPath,
33+
languageCodes as TranslationLang[],
34+
parseInt(revision as string),
35+
accessToken,
36+
);
37+
const { translations } = await formPublicationsService.getTranslations(
38+
formPath,
39+
languageCodes as TranslationLang[],
40+
);
41+
const formioTranslations = Object.fromEntries(
42+
Object.entries(translations).map(([key, values]) => [
43+
mapLanguageCodeToFormioFormat(key as TranslationLang),
44+
values,
45+
]),
46+
);
47+
const formioForm = formioFormsApiUtils.mapFormToNavForm(form);
48+
49+
req.body = { form: formioForm, translations: formioTranslations, formsApiForm: form };
50+
next();
51+
} catch (error) {
52+
next(error);
53+
}
54+
};
55+
56+
const unpublish: RequestHandler = async (req, _res, next) => {
57+
try {
58+
const { formPath } = req.params;
59+
const accessToken = req.headers.AzureAccessToken as string;
60+
await formPublicationsService.unpublish(formPath, accessToken);
61+
const form = await formsService.get(formPath);
62+
req.body = { formsApiForm: form };
63+
next();
64+
} catch (error) {
65+
next(error);
66+
}
67+
};
68+
69+
const getTranslations = async (req, res, next) => {
70+
const { formPath } = req.params;
71+
const { languageCodes } = req.query;
72+
try {
73+
const translations = await formPublicationsService.getTranslations(formPath, languageCodes);
74+
res.json(translations);
75+
} catch (error) {
76+
next(error);
77+
}
78+
};
79+
80+
const formPublications = { getAll, get, post, delete: unpublish, getTranslations };
81+
82+
export default formPublications;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import express from 'express';
2+
import authHandlers from '../helpers/authHandlers';
3+
import publishForm from '../publish-form';
4+
import unpublishForm from '../unpublish-form';
5+
import formPublications from './form-publications';
6+
7+
const formPublicationsRouter = express.Router();
8+
const { formsApiAuthHandler } = authHandlers;
9+
10+
formPublicationsRouter.get('/', formPublications.getAll);
11+
formPublicationsRouter.get('/:formPath', formPublications.get);
12+
formPublicationsRouter.post('/:formPath', formsApiAuthHandler, formPublications.post, publishForm);
13+
formPublicationsRouter.delete('/:formPath', formsApiAuthHandler, formPublications.delete, unpublishForm);
14+
formPublicationsRouter.get('/:formPath/translations', formPublications.getTranslations);
15+
16+
export default formPublicationsRouter;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { TranslationLang } from '@navikt/skjemadigitalisering-shared-domain';
2+
3+
const mapLanguageCodeToFormioFormat = (languageCode: TranslationLang) => {
4+
switch (languageCode) {
5+
case 'nn':
6+
return 'nn-NO';
7+
case 'en':
8+
return 'en';
9+
case 'nb':
10+
default:
11+
return 'nb-NO';
12+
}
13+
};
14+
15+
export { mapLanguageCodeToFormioFormat };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { FormsApiFormTranslation } from '@navikt/skjemadigitalisering-shared-domain';
2+
import { RequestHandler } from 'express';
3+
import { HttpError as OldHttpError } from '../../../fetchUtils';
4+
import { formTranslationsService } from '../../../services';
5+
import { HttpError } from '../helpers/errors';
6+
7+
const get: RequestHandler = async (req, res, next) => {
8+
const { formPath } = req.params;
9+
try {
10+
const translations = await formTranslationsService.get(formPath);
11+
res.json(translations);
12+
} catch (error) {
13+
next(error);
14+
}
15+
};
16+
17+
const post: RequestHandler = async (req, res, next) => {
18+
const { formPath } = req.params;
19+
const accessToken = req.headers.AzureAccessToken as string;
20+
const { key, nb, nn, en, globalTranslationId } = req.body as FormsApiFormTranslation;
21+
const body = globalTranslationId ? { key, globalTranslationId } : { key, nb, nn, en };
22+
try {
23+
const translation = await formTranslationsService.post(formPath, body, accessToken);
24+
res.status(201).json(translation);
25+
} catch (error) {
26+
if (error instanceof OldHttpError) {
27+
next(new HttpError(error.message, error.response.status));
28+
} else {
29+
next(error);
30+
}
31+
}
32+
};
33+
34+
const put: RequestHandler = async (req, res, next) => {
35+
const { formPath, id } = req.params;
36+
const { revision, nb, nn, en, globalTranslationId } = req.body as FormsApiFormTranslation;
37+
const accessToken = req.headers.AzureAccessToken as string;
38+
const body = globalTranslationId ? { globalTranslationId } : { nb, nn, en };
39+
try {
40+
const translation = await formTranslationsService.put(formPath, id, body, revision!, accessToken);
41+
res.json(translation);
42+
} catch (error) {
43+
if (error instanceof OldHttpError) {
44+
next(new HttpError(error.message, error.response.status));
45+
} else {
46+
next(error);
47+
}
48+
}
49+
};
50+
51+
const deleteTranslation: RequestHandler = async (req, res, next) => {
52+
const { formPath, id } = req.params;
53+
const accessToken = req.headers.AzureAccessToken as string;
54+
try {
55+
await formTranslationsService.delete(formPath, parseInt(id), accessToken);
56+
res.sendStatus(204);
57+
} catch (error) {
58+
if (error instanceof OldHttpError) {
59+
next(new HttpError(error.message, error.response.status));
60+
} else {
61+
next(error);
62+
}
63+
}
64+
};
65+
66+
const formTranslations = {
67+
get,
68+
post,
69+
put,
70+
delete: deleteTranslation,
71+
};
72+
export default formTranslations;

0 commit comments

Comments
 (0)