diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b2040834..5c09f25d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -48,7 +48,7 @@ jobs: deploy-til-dev: name: Deploy til dev-gcp needs: bygg-og-push-docker-image - if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/fjern-kandidatlister-med-stilling-fra-oversikt' + if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/mer-audit-logging' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/server/package.json b/server/package.json index 594ac614..b1d697c7 100644 --- a/server/package.json +++ b/server/package.json @@ -2,7 +2,8 @@ "scripts": { "build": "tsc --build", "start": "nodemon src/server.ts", - "test": "jest" + "test": "jest", + "test:watch": "jest --watch" }, "dependencies": { "compression": "^1.7.4", diff --git "a/server/src/kandidats\303\270k/elasticSearchTyper.ts" "b/server/src/kandidats\303\270k/elasticSearchTyper.ts" index a0e7a890..ef3c0721 100644 --- "a/server/src/kandidats\303\270k/elasticSearchTyper.ts" +++ "b/server/src/kandidats\303\270k/elasticSearchTyper.ts" @@ -11,6 +11,10 @@ export type SearchQuery = { }; }>; }; + term?: { + [felt: string]: string; + }; }; - _source: boolean | string[]; + _source?: boolean | string[]; + size?: number; }; diff --git "a/server/src/kandidats\303\270k/kandidats\303\270k.ts" "b/server/src/kandidats\303\270k/kandidats\303\270k.ts" index 8d553297..1501eb42 100644 --- "a/server/src/kandidats\303\270k/kandidats\303\270k.ts" +++ "b/server/src/kandidats\303\270k/kandidats\303\270k.ts" @@ -1,4 +1,4 @@ -import { RequestHandler } from 'express'; +import { Request, RequestHandler } from 'express'; import { hentGrupper, hentNavIdent } from '../azureAd'; import { auditLog, logger, opprettLoggmeldingForAuditlogg, secureLog } from '../logger'; import { retrieveToken } from '../middlewares'; @@ -58,34 +58,70 @@ export const leggTilAuthorizationForKandidatsøkEs = next(); }; -export const loggSøkPåFnrEllerAktørId: RequestHandler = async (request, _, next) => { - const erSøkPåKandidater = request.body && request.body._source !== false; +export const loggSøkPåFnrEllerAktørId: RequestHandler = (request, response, next) => { + try { + const requestOmSpesifikkPerson = requestBerOmSpesifikkPerson(request); - if (erSøkPåKandidater) { - try { - const fnrEllerAktørId = hentFnrEllerAktørIdFraESBody(request.body); + if (requestOmSpesifikkPerson !== null) { + const brukerensAccessToken = retrieveToken(request.headers); + const navIdent = hentNavIdent(brukerensAccessToken); - if (fnrEllerAktørId) { - const brukerensAccessToken = retrieveToken(request.headers); - const navIdent = hentNavIdent(brukerensAccessToken); - - const melding = opprettLoggmeldingForAuditlogg( - 'NAV-ansatt har gjort spesifikt kandidatsøk på brukeren', - fnrEllerAktørId, - navIdent - ); + const melding = opprettLoggmeldingForAuditlogg( + requestOmSpesifikkPerson.melding, + requestOmSpesifikkPerson.fnrEllerAktørId, + navIdent + ); - auditLog.info(melding); - } - } catch (e) { - logger.error('Klarte ikke å logge søk på fnr eller aktørId:', e); + auditLog.info(melding); + secureLog.info(`Auditlogget handling: ${melding}`); } + } catch (e) { + const feilmelding = + 'Klarte ikke å verifisere eller logge henting av persondata via kandidatsøk-proxy:'; + logger.error(feilmelding, e); + + return response.status(500).send(feilmelding); } next(); }; -export const hentFnrEllerAktørIdFraESBody = (request: SearchQuery): string | null => { +type MeldingTilAuditlog = { + melding: string; + fnrEllerAktørId: string; +}; + +const requestBerOmSpesifikkPerson = ( + request: Request +): null | MeldingTilAuditlog => { + const berOmData = request.body && request.body._source !== false; + + if (!berOmData) { + return null; + } + + const idInniSpesifikkPersonQuery = erSpesifikkPersonQuery(request.body); + const idInniHentKandidatQuery = erHentKandidatQuery(request.body); + const idInniFinnStillingQuery = erFinnStillingQuery(request.body); + + if (idInniSpesifikkPersonQuery) { + return { + melding: 'NAV-ansatt har gjort spesifikt kandidatsøk på brukeren', + fnrEllerAktørId: idInniSpesifikkPersonQuery, + }; + } else if (idInniHentKandidatQuery) { + return { + melding: "NAV-ansatt har åpnet CV'en til bruker", + fnrEllerAktørId: idInniHentKandidatQuery, + }; + } else if (idInniFinnStillingQuery) { + return null; // TODO: Bør audit-logges? + } + + return null; +}; + +export const erSpesifikkPersonQuery = (request: SearchQuery): string | null => { let fnrEllerAktørId = null; request.query?.bool?.must?.forEach((mustQuery) => @@ -98,3 +134,27 @@ export const hentFnrEllerAktørIdFraESBody = (request: SearchQuery): string | nu return fnrEllerAktørId; }; + +export const erHentKandidatQuery = (request: SearchQuery): string | null => { + if ( + request.size === 1 && + request._source === undefined && + request.query?.term?.['kandidatnr'] !== undefined + ) { + return request.query.term['kandidatnr']; + } + + return null; +}; + +export const erFinnStillingQuery = (request: SearchQuery): string | null => { + if ( + request.size === 1 && + request._source && + request.query?.term?.['kandidatnr'] !== undefined + ) { + return request.query.term['kandidatnr']; + } + + return null; +}; diff --git a/server/src/logger.ts b/server/src/logger.ts index cf1e1cb7..d4e7fe44 100644 --- a/server/src/logger.ts +++ b/server/src/logger.ts @@ -1,7 +1,7 @@ import fs from 'fs'; +import os from 'os'; import winston from 'winston'; import winstonSyslog from 'winston-syslog'; -import os from 'os'; // Sett tidssonen eksplisitt for å sikre riktig timestamp i logging til archsight process.env.TZ = 'Europe/Oslo'; @@ -44,15 +44,19 @@ export const auditLog = winston.createLogger({ export const opprettLoggmeldingForAuditlogg = ( melding: string, fnrEllerAktørId: string, - navIdent: string + navIdent: string, + end = currentTimeForAuditlogg() ): string => { const header = `CEF:0|Rekrutteringsbistand|${NAIS_APP_NAME}|1.0|audit:access|Sporingslogg|INFO`; + const extension = `flexString1=Permit\ msg=${melding}\ duid=${fnrEllerAktørId} flexString1Label=Decision\ - end=${Date.now()}\ + end=${end}\ suid=${navIdent}`.replace(/\s+/g, ' '); return `${header}|${extension}`; }; + +export const currentTimeForAuditlogg = () => Date.now(); diff --git a/server/test/Auditlogging.test.ts b/server/test/Auditlogging.test.ts new file mode 100644 index 00000000..179f3f9b --- /dev/null +++ b/server/test/Auditlogging.test.ts @@ -0,0 +1,89 @@ +import { beforeEach, describe, expect, jest, test } from '@jest/globals'; +import { NextFunction, Request, Response } from 'express'; +import * as azureAd from '../src/azureAd'; +import * as kandidatsøk from '../src/kandidatsøk/kandidatsøk'; +import * as logger from '../src/logger'; +import * as queries from './queriesMotSpesifikkPerson'; + +describe('Auditlogging av personspesifikt kandidatsøk', () => { + let mockRequest: Partial>; + let mockResponse: Partial; + let nextFunction: NextFunction = jest.fn(); + + beforeEach(() => { + mockResponse = { + status: jest.fn(() => mockResponse), + send: jest.fn(), + } as Partial; + + mockRequest = { + headers: { + authorization: '', + }, + }; + + nextFunction = jest.fn(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + test('Kall mot kandidatsøk med spesifikk person-query på fødselsnummer skal logges', async () => { + const dateNow = 1; + const navIdent = 'A123456'; + const personId = '12345678910'; + const melding = `CEF:0|Rekrutteringsbistand|undefined|1.0|audit:access|Sporingslogg|INFO|flexString1=Permit msg=NAV-ansatt har gjort spesifikt kandidatsøk på brukeren duid=${personId} flexString1Label=Decision end=${dateNow} suid=${navIdent}`; + + mockRequest.body = queries.queryTilKandidatsøkMedAktørIdOgFødselsnummer(personId); + + jest.spyOn(logger, 'currentTimeForAuditlogg').mockReturnValue(1); + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue(navIdent); + const auditLog = jest.spyOn(logger.auditLog, 'info'); + const secureLog = jest.spyOn(logger.secureLog, 'info'); + + auditLog.mockImplementation(() => logger.auditLog); + secureLog.mockImplementation(() => logger.secureLog); + + kandidatsøk.loggSøkPåFnrEllerAktørId( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalled(); + expect(auditLog).toBeCalledTimes(1); + expect(auditLog).toHaveBeenCalledWith(melding); + expect(secureLog).toBeCalledTimes(1); + expect(secureLog).toHaveBeenCalledWith('Auditlogget handling: ' + melding); + }); + + test('Kall mot kandidatsøk med hent person-query på fødselsnummer skal logges', async () => { + const dateNow = 1; + const navIdent = 'A123456'; + const personId = '12345678910'; + const melding = `CEF:0|Rekrutteringsbistand|undefined|1.0|audit:access|Sporingslogg|INFO|flexString1=Permit msg=NAV-ansatt har åpnet CV'en til bruker duid=${personId} flexString1Label=Decision end=${dateNow} suid=${navIdent}`; + + mockRequest.body = queries.queryTilHentKandidat(personId); + + jest.spyOn(logger, 'currentTimeForAuditlogg').mockReturnValue(1); + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue(navIdent); + const auditLog = jest.spyOn(logger.auditLog, 'info'); + const secureLog = jest.spyOn(logger.secureLog, 'info'); + + auditLog.mockImplementation((_) => logger.auditLog); + secureLog.mockImplementation(() => logger.secureLog); + + kandidatsøk.loggSøkPåFnrEllerAktørId( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalled(); + expect(auditLog).toBeCalledTimes(1); + expect(auditLog).toHaveBeenCalledWith(melding); + expect(secureLog).toBeCalledTimes(1); + expect(secureLog).toHaveBeenCalledWith('Auditlogget handling: ' + melding); + }); +}); diff --git a/server/test/Tilgangskontroll.test.ts b/server/test/Tilgangskontroll.test.ts new file mode 100644 index 00000000..822139a6 --- /dev/null +++ b/server/test/Tilgangskontroll.test.ts @@ -0,0 +1,88 @@ +import { beforeEach, describe, expect, jest, test } from '@jest/globals'; +import { NextFunction, Request, Response } from 'express'; +import * as azureAd from '../src/azureAd'; +import * as kandidatsøk from '../src/kandidatsøk/kandidatsøk'; +import * as middlewares from '../src/middlewares'; + +describe('Tilgangskontroll for kandidatsøket', () => { + let mockRequest: Partial; + let mockResponse: Partial; + let nextFunction: NextFunction = jest.fn(); + + beforeEach(() => { + mockResponse = { + status: jest.fn(() => mockResponse), + send: jest.fn(), + } as Partial; + + mockRequest = { + headers: { + authorization: '', + }, + body: {}, + }; + + nextFunction = jest.fn(); + }); + + test('En bruker med ModiaGenerellTilgang skal få tilgang til kandidatsøket', async () => { + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); + jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([ + kandidatsøk.AD_GRUPPE_MODIA_GENERELL_TILGANG!, + ]); + + kandidatsøk.harTilgangTilKandidatsøk( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalled(); + }); + + test('En bruker med ModiaOppfølging skal få tilgang til kandidatsøket', async () => { + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); + jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([ + kandidatsøk.AD_GRUPPE_MODIA_OPPFOLGING!, + ]); + + kandidatsøk.harTilgangTilKandidatsøk( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalled(); + }); + + test('En bruker med andre tilganger skal ikke få tilgang til kandidatsøket', async () => { + const andreTilganger = ['en-annen-tilgang']; + + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); + jest.spyOn(azureAd, 'hentGrupper').mockReturnValue(andreTilganger); + + kandidatsøk.harTilgangTilKandidatsøk( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalledTimes(0); + expect(mockResponse.status).toBeCalledWith(403); + }); + + test('En bruker uten noen tilganger skal ikke få tilgang til kandidatsøket', async () => { + jest.spyOn(middlewares, 'retrieveToken').mockReturnValue(''); + jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); + jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([]); + + kandidatsøk.harTilgangTilKandidatsøk( + mockRequest as Request, + mockResponse as Response, + nextFunction + ); + + expect(nextFunction).toBeCalledTimes(0); + expect(mockResponse.status).toBeCalledWith(403); + }); +}); diff --git a/server/test/erSpesifikkPersonQuery.test.ts b/server/test/erSpesifikkPersonQuery.test.ts new file mode 100644 index 00000000..270c1e95 --- /dev/null +++ b/server/test/erSpesifikkPersonQuery.test.ts @@ -0,0 +1,120 @@ +import { describe, expect, test } from '@jest/globals'; +import { EsQuery } from '../../src/felles/domene/elastic/ElasticSearch'; +import Kandidat from '../../src/felles/domene/kandidat/Kandidat'; +import * as kandidatsøk from '../src/kandidatsøk/kandidatsøk'; + +describe('ES body for søk', () => { + let queryMock = (bool?: object): EsQuery => { + return { + query: { + bool: { + must: [ + { + bool: bool, + }, + ], + }, + }, + _source: [ + 'fodselsnummer', + 'fornavn', + 'etternavn', + 'arenaKandidatnr', + 'kvalifiseringsgruppekode', + 'yrkeJobbonskerObj', + 'geografiJobbonsker', + ], + }; + }; + + test('Er ES body med søk på fødselsnummer og aktørId', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery( + queryMock({ + should: [ + { + term: { + aktorId: '21909899211', + }, + }, + { + term: { + fodselsnummer: '21909899211', + }, + }, + ], + }) + ); + + expect(resultat).toBeTruthy(); + }); + + test('Er ES body med søk på fødselsnummer', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery( + queryMock({ + should: [ + { + term: { + fodselsnummer: '21909899211', + }, + }, + ], + }) + ); + expect(resultat).toBeTruthy(); + }); + + test('Er ES body med søk på aktørId', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery( + queryMock({ + should: [ + { + term: { + aktorId: '21909899211', + }, + }, + ], + }) + ); + expect(resultat).toBeTruthy(); + }); + + test('Er ES body uten søk på fødselsnummer eller aktørId', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery(queryMock()); + expect(resultat).toBeFalsy(); + }); + + test('Henter fnr fra ES body når det finnes', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery( + queryMock({ + should: [ + { + term: { + aktorId: '21909899211', + }, + }, + { + term: { + fodselsnummer: '10108000398', + }, + }, + ], + }) + ); + expect(resultat).toBe('10108000398'); + }); + + test('Henter aktørid fra ES body når fnr ikke finnes', async () => { + const resultat = kandidatsøk.erSpesifikkPersonQuery( + queryMock({ + should: [ + { + term: { + aktorId: '21909899211', + }, + }, + ], + }) + ); + expect(resultat).toBe('21909899211'); + }); +}); diff --git "a/server/test/kandidats\303\270k.test.ts" "b/server/test/kandidats\303\270k.test.ts" deleted file mode 100644 index 9936be41..00000000 --- "a/server/test/kandidats\303\270k.test.ts" +++ /dev/null @@ -1,204 +0,0 @@ -import { beforeEach, describe, expect, jest, test } from '@jest/globals'; -import { NextFunction, Request, Response } from 'express'; -import * as azureAd from '../src/azureAd'; -import { SearchQuery } from '../src/kandidatsøk/elasticSearchTyper'; -import * as kandidatsøk from '../src/kandidatsøk/kandidatsøk'; -import * as middlewares from '../src/middlewares'; - -describe('Tilgangskontroll for kandidatsøket', () => { - let mockRequest: Partial; - let mockResponse: Partial; - let nextFunction: NextFunction = jest.fn(); - - beforeEach(() => { - mockResponse = { - status: jest.fn(() => mockResponse), - send: jest.fn(), - } as Partial; - - mockRequest = { - headers: { - authorization: '', - }, - body: {}, - }; - - nextFunction = jest.fn(); - }); - - test('En bruker med ModiaGenerellTilgang skal få tilgang til kandidatsøket', async () => { - jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); - jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([ - kandidatsøk.AD_GRUPPE_MODIA_GENERELL_TILGANG!, - ]); - - await kandidatsøk.harTilgangTilKandidatsøk( - mockRequest as Request, - mockResponse as Response, - nextFunction - ); - - expect(nextFunction).toBeCalled(); - }); - - test('En bruker med ModiaOppfølging skal få tilgang til kandidatsøket', async () => { - jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); - jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([ - kandidatsøk.AD_GRUPPE_MODIA_OPPFOLGING!, - ]); - - await kandidatsøk.harTilgangTilKandidatsøk( - mockRequest as Request, - mockResponse as Response, - nextFunction - ); - - expect(nextFunction).toBeCalled(); - }); - - test('En bruker med andre tilganger skal ikke få tilgang til kandidatsøket', async () => { - const andreTilganger = ['en-annen-tilgang']; - - jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); - jest.spyOn(azureAd, 'hentGrupper').mockReturnValue(andreTilganger); - - await kandidatsøk.harTilgangTilKandidatsøk( - mockRequest as Request, - mockResponse as Response, - nextFunction - ); - - expect(nextFunction).toBeCalledTimes(0); - expect(mockResponse.status).toBeCalledWith(403); - }); - - test('En bruker uten noen tilganger skal ikke få tilgang til kandidatsøket', async () => { - jest.spyOn(middlewares, 'retrieveToken').mockReturnValue(''); - jest.spyOn(azureAd, 'hentNavIdent').mockReturnValue('A123456'); - jest.spyOn(azureAd, 'hentGrupper').mockReturnValue([]); - - await kandidatsøk.harTilgangTilKandidatsøk( - mockRequest as Request, - mockResponse as Response, - nextFunction - ); - - expect(nextFunction).toBeCalledTimes(0); - expect(mockResponse.status).toBeCalledWith(403); - }); -}); - -describe('ES body for søk', () => { - let queryMock = (bool?: object): SearchQuery => { - return { - query: { - bool: { - must: [ - { - bool: bool, - }, - ], - }, - }, - _source: [ - 'fodselsnummer', - 'fornavn', - 'etternavn', - 'arenaKandidatnr', - 'kvalifiseringsgruppekode', - 'yrkeJobbonskerObj', - 'geografiJobbonsker', - ], - }; - }; - - test('Er ES body med søk på fødselsnummer og aktørId', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody( - queryMock({ - should: [ - { - term: { - aktorId: '21909899211', - }, - }, - { - term: { - fodselsnummer: '21909899211', - }, - }, - ], - }) - ); - expect(resultat).toBeTruthy(); - }); - - test('Er ES body med søk på fødselsnummer', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody( - queryMock({ - should: [ - { - term: { - fodselsnummer: '21909899211', - }, - }, - ], - }) - ); - expect(resultat).toBeTruthy(); - }); - - test('Er ES body med søk på aktørId', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody( - queryMock({ - should: [ - { - term: { - aktorId: '21909899211', - }, - }, - ], - }) - ); - expect(resultat).toBeTruthy(); - }); - - test('Er ES body uten søk på fødselsnummer eller aktørId', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody(queryMock()); - expect(resultat).toBeFalsy(); - }); - - test('Henter fnr fra ES body når det finnes', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody( - queryMock({ - should: [ - { - term: { - aktorId: '21909899211', - }, - }, - { - term: { - fodselsnummer: '10108000398', - }, - }, - ], - }) - ); - expect(resultat).toBe('10108000398'); - }); - - test('Henter aktørid fra ES body når fnr ikke finnes', async () => { - const resultat = kandidatsøk.hentFnrEllerAktørIdFraESBody( - queryMock({ - should: [ - { - term: { - aktorId: '21909899211', - }, - }, - ], - }) - ); - expect(resultat).toBe('21909899211'); - }); -}); diff --git a/server/test/queriesMotSpesifikkPerson.ts b/server/test/queriesMotSpesifikkPerson.ts new file mode 100644 index 00000000..14ba8fb7 --- /dev/null +++ b/server/test/queriesMotSpesifikkPerson.ts @@ -0,0 +1,42 @@ +import { EsQuery } from '../../src/felles/domene/elastic/ElasticSearch'; +import Kandidat from '../../src/felles/domene/kandidat/Kandidat'; + +export const queryTilKandidatsøkMedAktørIdOgFødselsnummer = ( + personId: string +): EsQuery => ({ + query: { + bool: { + must: [ + { + bool: { + should: [ + { term: { aktorId: personId } }, + { term: { fodselsnummer: personId } }, + ], + }, + }, + { terms: { kvalifiseringsgruppekode: ['BATT', 'BFORM', 'IKVAL', 'VARIG'] } }, + ], + }, + }, + size: 25, + from: 0, + track_total_hits: true, + sort: { tidsstempel: { order: 'desc' } }, + _source: [ + 'fodselsnummer', + 'fornavn', + 'etternavn', + 'arenaKandidatnr', + 'kvalifiseringsgruppekode', + 'yrkeJobbonskerObj', + 'geografiJobbonsker', + 'kommuneNavn', + 'postnummer', + ], +}); + +export const queryTilHentKandidat = (kandidatnr: string): EsQuery => ({ + size: 1, + query: { term: { kandidatnr: kandidatnr } }, +}); diff --git a/src/felles/domene/elastic/ElasticSearch.ts b/src/felles/domene/elastic/ElasticSearch.ts index 2dbd1f76..aa0a16df 100644 --- a/src/felles/domene/elastic/ElasticSearch.ts +++ b/src/felles/domene/elastic/ElasticSearch.ts @@ -21,7 +21,7 @@ export type EsQuery = { query: string; } >; - bool?: object; + bool?: any; match_all?: object; multi_match?: { query: string; diff --git a/src/kandidat/api/api.ts b/src/kandidat/api/api.ts index 8747c6ed..96ac1597 100644 --- a/src/kandidat/api/api.ts +++ b/src/kandidat/api/api.ts @@ -1,5 +1,7 @@ import { api, post } from 'felles/api'; +import { EsQuery, EsResponse } from 'felles/domene/elastic/ElasticSearch'; import Cv from 'felles/domene/kandidat/Cv'; +import Kandidat from 'felles/domene/kandidat/Kandidat'; import { Kandidatstatus, Kandidatutfall, @@ -11,8 +13,6 @@ import { FormidlingAvUsynligKandidatOutboundDto } from '../kandidatliste/modaler import { KandidatlisteDto } from '../kandidatlisteoversikt/modaler/Kandidatlisteskjema'; import { MineKandidatlister } from '../kandidatside/fraSøkUtenKontekst/lagre-kandidat-modal/useMineKandidatlister'; import { deleteJsonMedType, deleteReq, fetchJson, postJson, putJson } from './fetchUtils'; -import { EsQuery, EsResponse } from 'felles/domene/elastic/ElasticSearch'; -import Kandidat from 'felles/domene/kandidat/Kandidat'; export const ENHETSREGISTER_API = `/${api.stilling}/search-api`;