diff --git a/frontend/package.json b/frontend/package.json index b2a451c7c..654f3f75f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -94,7 +94,6 @@ "identity-obj-proxy": "^3.0.0", "jest": "^29.7.0", "jest-extended": "^4.0.2", - "jest-fetch-mock": "^3.0.3", "jest-watch-typeahead": "^2.2.2", "randomstring": "^1.3.0", "react-dev-utils": "^12.0.1", diff --git a/server/package.json b/server/package.json index 330c23afe..0b64a9b8b 100644 --- a/server/package.json +++ b/server/package.json @@ -33,6 +33,7 @@ "@zerologementvacant/schemas": "workspace:*", "@zerologementvacant/utils": "workspace:*", "async": "^3.2.6", + "axios": "^1.7.7", "bcryptjs": "^2.4.3", "cli-progress": "^3.12.0", "commander": "^12.1.0", @@ -66,7 +67,6 @@ "multer": "^1.4.5-lts.1", "multer-s3": "^3.0.1", "nock": "^13.5.5", - "node-fetch": "^3.3.2", "nodemailer": "^6.9.15", "parse-redis-url-simple": "^1.0.2", "pdf-lib": "^1.17.1", @@ -123,7 +123,6 @@ "@types/wuzzy": "^0.1.3", "jest": "^29.7.0", "jest-extended": "^4.0.2", - "jest-fetch-mock": "^3.0.3", "jest-sorted": "^1.0.15", "nodemailer-mock": "^2.0.6", "nodemon": "^3.1.7", diff --git a/server/src/controllers/datafoncierHousingController.test.ts b/server/src/controllers/datafoncierHousingController.test.ts index 9690601f5..25bd7d180 100644 --- a/server/src/controllers/datafoncierHousingController.test.ts +++ b/server/src/controllers/datafoncierHousingController.test.ts @@ -7,13 +7,13 @@ import { genDatafoncierHousing, genEstablishmentApi, genUserApi, - oneOf, + oneOf } from '~/test/testFixtures'; import { DatafoncierHouses } from '~/repositories/datafoncierHousingRepository'; import { formatUserApi, Users } from '~/repositories/userRepository'; import { Establishments, - formatEstablishmentApi, + formatEstablishmentApi } from '~/repositories/establishmentRepository'; describe('Datafoncier housing controller', () => { @@ -55,13 +55,6 @@ describe('Datafoncier housing controller', () => { }); it('should return "not found" otherwise', async () => { - fetchMock.mockIf( - (request) => request.url.endsWith(`/ff/locaux/missing`), - async () => ({ - status: 404, - }), - ); - const { status } = await request(app) .get(testRoute('missing')) .use(tokenProvider(user)); diff --git a/server/src/infra/database/seeds/development/20240404235458_housings.ts b/server/src/infra/database/seeds/development/20240404235458_housings.ts index 04c6d13cb..4c80ad91f 100644 --- a/server/src/infra/database/seeds/development/20240404235458_housings.ts +++ b/server/src/infra/database/seeds/development/20240404235458_housings.ts @@ -1,7 +1,9 @@ import { faker } from '@faker-js/faker/locale/fr'; +import * as turf from '@turf/turf'; import async from 'async'; import { Knex } from 'knex'; +import { AddressKinds } from '@zerologementvacant/models'; import { Establishments } from '~/repositories/establishmentRepository'; import { HousingApi } from '~/models/HousingApi'; import { genHousingApi, genOwnerApi } from '~/test/testFixtures'; @@ -16,23 +18,113 @@ import { formatHousingOwnerApi, housingOwnersTable } from '~/repositories/housingOwnerRepository'; +import { Feature, MultiPolygon, Polygon, Position } from 'geojson'; +import { createBanAPI } from '~/services/ban/ban-api'; +import { MarkRequired } from 'ts-essentials'; +import { + banAddressesTable, + formatAddressApi +} from '~/repositories/banAddressesRepository'; +import { AddressApi } from '~/models/AddressApi'; export async function seed(knex: Knex): Promise { - const establishments = await Establishments(knex).where({ available: true }); + const ban = createBanAPI(); + + await knex.raw(`TRUNCATE TABLE ${housingOwnersTable} CASCADE`); + await knex.raw(`TRUNCATE TABLE ${housingTable} CASCADE`); + await knex.raw(`TRUNCATE TABLE ${ownerTable} CASCADE`); + const establishments = await Establishments(knex).where({ available: true }); await async.forEachSeries(establishments, async (establishment) => { - const housings: ReadonlyArray = faker.helpers.multiple( - () => - genHousingApi( - faker.helpers.arrayElement(establishment.localities_geo_code) - ), - { - count: { - min: 100, - max: 10000 + const id = + establishment.kind === 'Commune' + ? establishment.localities_geo_code[0] + : establishment.siren; + const kind = establishment.kind === 'Commune' ? 'communes' : 'epcis'; + const response = await fetch( + `https://geo.api.gouv.fr/${kind}/${id}?format=geojson&geometry=contour` + ); + if (!response.ok) { + const error = await response.json(); + console.log(error); + throw new Error('Failed to fetch geojson'); + } + + const epci = await response.json(); + const contour = (epci as Feature).geometry; + + const baseHousings: ReadonlyArray< + MarkRequired + > = faker.helpers + .multiple( + () => + genHousingApi( + faker.helpers.arrayElement(establishment.localities_geo_code) + ), + { + count: { + min: 100, + max: 10000 + } } - } + ) + // Put the housing inside the establishment perimeter + .map((housing) => { + const point = generatePointInside(contour); + return { + ...housing, + longitude: point[0], + latitude: point[1] + }; + }); + + // Infer housing addresses using the generated coordinates + const points = baseHousings.map((housing) => ({ + refId: housing.id, + geoCode: housing.geoCode, + longitude: housing.longitude, + latitude: housing.latitude + })); + const addresses = await ban.reverseMany(points).then((addresses) => { + return addresses.filter((address) => !!address.label); + }); + const housings = baseHousings + .filter((housing) => { + return addresses.some( + (address) => + address.refId === housing.id && address.geoCode === housing.geoCode + ); + }) + .map((housing, i) => { + const address = addresses[i]; + if (address.refId !== housing.id) { + throw new Error('Should never happen'); + } + return { + ...housing, + rawAddress: [address.label] + }; + }); + + // Insert housings + console.log(`Inserting ${housings.length} housings...`, { + establishment: establishment.name + }); + await knex.batchInsert(housingTable, housings.map(formatHousingRecordApi)); + + // Insert BAN housing addresses + const housingAddresses: ReadonlyArray = addresses.map( + (address) => ({ ...address, addressKind: AddressKinds.Housing }) + ); + console.log( + `Inserting ${housingAddresses.length} BAN housing addresses...`, + { establishment: establishment.name } + ); + await knex.batchInsert( + banAddressesTable, + housingAddresses.map(formatAddressApi) ); + const housingOwners: ReadonlyArray = housings.flatMap( (housing) => { const owners = faker.helpers.multiple(() => genOwnerApi(), { @@ -55,12 +147,26 @@ export async function seed(knex: Knex): Promise { } ); const owners: ReadonlyArray = housingOwners.flat(); - - await knex.batchInsert(housingTable, housings.map(formatHousingRecordApi)); + console.log(`Inserting ${owners.length} owners...`, { + establishment: establishment.name + }); await knex.batchInsert(ownerTable, owners.map(formatOwnerApi)); + + console.log(`Inserting ${housingOwners.length} housing owners...`, { + establishment: establishment.name + }); await knex.batchInsert( housingOwnersTable, housingOwners.map(formatHousingOwnerApi) ); }); } + +function generatePointInside(perimeter: Polygon | MultiPolygon): Position { + function generate(): Position { + const bbox = turf.bbox(perimeter); + const point = turf.randomPosition(bbox); + return turf.booleanPointInPolygon(point, perimeter) ? point : generate(); + } + return generate(); +} diff --git a/server/src/services/ban/ban-api.ts b/server/src/services/ban/ban-api.ts new file mode 100644 index 000000000..3cd3a3374 --- /dev/null +++ b/server/src/services/ban/ban-api.ts @@ -0,0 +1,142 @@ +import axios from 'axios'; +import { parse as fromCSV } from 'csv-parse/sync'; +import { stringify as toCSV } from 'csv-stringify/sync'; + +import { Address, AddressQuery, BAN, Point } from '~/services/ban/ban'; + +class BanAPI implements BAN { + readonly http = axios.create({ + baseURL: 'https://api-adresse.data.gouv.fr' + }); + + async searchMany( + queries: ReadonlyArray + ): Promise> { + if (!queries.length) { + throw new Error('Must contain at least one query'); + } + + const [query] = queries; + const columns = listColumns(query); + const csv = toCSV(queries as Q[], { + header: true, + columns + }); + const blob = new Blob([csv], { type: 'text/csv' }); + const form = new FormData(); + form.append('data', blob, 'search.csv'); + + // Add columns + columns.forEach((column) => { + form.append('columns', column); + }); + + // Tells the API that geoCode is an INSEE code + form.append('citycode', 'geoCode'); + form.append('result_columns', 'result_id'); + form.append('result_columns', 'result_label'); + form.append('result_columns', 'result_type'); + form.append('result_columns', 'result_housenumber'); + form.append('result_columns', 'result_street'); + form.append('result_columns', 'result_postcode'); + form.append('result_columns', 'result_city'); + form.append('result_columns', 'latitude'); + form.append('result_columns', 'longitude'); + form.append('result_columns', 'result_score'); + + const { data } = await this.http.post('/search/csv', form); + const records: ReadonlyArray = fromCSV(data, { + columns: true + }); + return records.filter((record) => !!record.result_id).map
(map); + } + + async reverseMany

( + points: ReadonlyArray

+ ): Promise> { + if (!points.length) { + throw new Error('Must contain at least one point'); + } + + const columns = listColumns(points[0]); + const csv = toCSV(points as P[], { + header: true, + columns + }); + const blob = new Blob([csv], { type: 'text/csv' }); + const form = new FormData(); + form.append('data', blob, 'reverse.csv'); + + // Add columns + columns.forEach((column) => { + form.append('columns', column); + }); + + // Tells the API that geoCode is an INSEE code + + form.append('citycode', 'geoCode'); + form.append('result_columns', 'result_id'); + form.append('result_columns', 'result_label'); + form.append('result_columns', 'result_type'); + form.append('result_columns', 'result_housenumber'); + form.append('result_columns', 'result_street'); + form.append('result_columns', 'result_postcode'); + form.append('result_columns', 'result_city'); + form.append('result_columns', 'latitude'); + form.append('result_columns', 'longitude'); + form.append('result_columns', 'result_score'); + + const { data } = await this.http.post('/reverse/csv', form); + const records: ReadonlyArray = fromCSV(data, { + columns: true + }); + return records.map

(map); + } +} + +interface BanAddress { + result_id: string; + result_label: string; + result_housenumber: string; + result_street: string; + result_postcode: string; + result_city: string; + latitude: string; + longitude: string; + result_score: string; +} + +function listColumns(a: A): ReadonlyArray { + return Object.keys(a); +} + +function map(address: BanAddress & A): Address & A { + const { + result_id, + result_label, + result_housenumber, + result_street, + result_postcode, + result_city, + result_score, + latitude, + longitude, + ...rest + } = address; + return { + ...(rest as unknown as A), + id: result_id, + label: result_label, + houseNumber: result_housenumber, + street: result_street, + postalCode: result_postcode, + city: result_city, + latitude: Number(latitude), + longitude: Number(longitude), + score: Number(result_score) + }; +} + +export function createBanAPI(): BAN { + return new BanAPI(); +} diff --git a/server/src/services/ban/ban.ts b/server/src/services/ban/ban.ts new file mode 100644 index 000000000..5fcfc9775 --- /dev/null +++ b/server/src/services/ban/ban.ts @@ -0,0 +1,29 @@ +export interface AddressQuery { + label: string; +} + +export interface Address { + id: string; + label: string; + houseNumber: string; + street: string; + postalCode: string; + city: string; + latitude: number; + longitude: number; + score: number; +} + +export interface Point { + longitude: number; + latitude: number; +} + +export interface BAN { + searchMany( + addresses: ReadonlyArray + ): Promise>; + reverseMany

( + points: ReadonlyArray

+ ): Promise>; +} diff --git a/server/src/test/setup-tests.ts b/server/src/test/setup-tests.ts index 8d1e11c76..7077d71bd 100644 --- a/server/src/test/setup-tests.ts +++ b/server/src/test/setup-tests.ts @@ -1,22 +1,22 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { enableFetchMocks } from 'jest-fetch-mock'; import 'jest-extended'; import 'jest-sorted'; import type { Jobs, Queue } from '@zerologementvacant/queue'; -enableFetchMocks(); - jest.mock('~/infra/queue', () => { return { add( + // eslint-disable-next-line @typescript-eslint/no-unused-vars job: K, + // eslint-disable-next-line @typescript-eslint/no-unused-vars data: Parameters[0] ): Promise { return Promise.resolve(); }, on( + // eslint-disable-next-line @typescript-eslint/no-unused-vars job: K, + // eslint-disable-next-line @typescript-eslint/no-unused-vars callback: (returned: ReturnType) => void ) { return; @@ -26,7 +26,3 @@ jest.mock('~/infra/queue', () => { } }; }); - -global.beforeEach(() => { - fetchMock.resetMocks(); -}); diff --git a/yarn.lock b/yarn.lock index 1a3bc7d6f..90d21d5b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -801,7 +801,7 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.9": +"@babel/compat-data@npm:^7.22.6": version: 7.26.2 resolution: "@babel/compat-data@npm:7.26.2" checksum: 10c0/c9b5f3724828d17f728a778f9d66c19b55c018d0d76de6d731178cca64f182c22b71400a73bf2b65dcc4fcfe52b630088a94d5902911b54206aa90e3ffe07d12 @@ -877,7 +877,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.25.9": +"@babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.25.9 resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" dependencies: @@ -905,20 +905,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6": - version: 7.25.9 - resolution: "@babel/helper-compilation-targets@npm:7.25.9" - dependencies: - "@babel/compat-data": "npm:^7.25.9" - "@babel/helper-validator-option": "npm:^7.25.9" - browserslist: "npm:^4.24.0" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10c0/a6b26a1e4222e69ef8e62ee19374308f060b007828bc11c65025ecc9e814aba21ff2175d6d3f8bf53c863edd728ee8f94ba7870f8f90a37d39552ad9933a8aaa - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.25.7": +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-compilation-targets@npm:7.25.7" dependencies: @@ -931,24 +918,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0": - version: 7.25.9 - resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.25.9" - "@babel/helper-member-expression-to-functions": "npm:^7.25.9" - "@babel/helper-optimise-call-expression": "npm:^7.25.9" - "@babel/helper-replace-supers": "npm:^7.25.9" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/b2bdd39f38056a76b9ba00ec5b209dd84f5c5ebd998d0f4033cf0e73d5f2c357fbb49d1ce52db77a2709fb29ee22321f84a5734dc9914849bdfee9ad12ce8caf - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.25.7": +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-create-class-features-plugin@npm:7.25.7" dependencies: @@ -965,20 +935,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6": - version: 7.25.9 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.9" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.25.9" - regexpu-core: "npm:^6.1.1" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/3adc60a758febbf07d65a15eaccab1f7b9fcc55e7141e59122f13c9f81fc0d1cce4525b7f4af50285d27c93b34c859fd2c39c39820c5fb92211898c3bbdc77ef - languageName: node - linkType: hard - -"@babel/helper-create-regexp-features-plugin@npm:^7.25.7": +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.7" dependencies: @@ -1016,27 +973,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" - dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10c0/e08c7616f111e1fb56f398365e78858e26e466d4ac46dff25921adc5ccae9b232f66e952a2f4162bbe336627ba336c7fd9eca4835b6548935973d3380d77eaff - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7": - version: 7.25.9 - resolution: "@babel/helper-module-imports@npm:7.25.9" - dependencies: - "@babel/traverse": "npm:^7.25.9" - "@babel/types": "npm:^7.25.9" - checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.25.7": +"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-module-imports@npm:7.25.7" dependencies: @@ -1069,15 +1006,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" - dependencies: - "@babel/types": "npm:^7.25.9" - checksum: 10c0/90203e6607edeadd2a154940803fd616c0ed92c1013d6774c4b8eb491f1a5a3448b68faae6268141caa5c456e55e3ee49a4ed2bd7ddaf2365daea321c435914c - languageName: node - linkType: hard - "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": version: 7.25.9 resolution: "@babel/helper-plugin-utils@npm:7.25.9" @@ -1118,19 +1046,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-replace-supers@npm:7.25.9" - dependencies: - "@babel/helper-member-expression-to-functions": "npm:^7.25.9" - "@babel/helper-optimise-call-expression": "npm:^7.25.9" - "@babel/traverse": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/0b40d7d2925bd3ba4223b3519e2e4d2456d471ad69aa458f1c1d1783c80b522c61f8237d3a52afc9e47c7174129bbba650df06393a6787d5722f2ec7f223c3f4 - languageName: node - linkType: hard - "@babel/helper-simple-access@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-simple-access@npm:7.25.7" @@ -1141,7 +1056,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0": version: 7.25.9 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" dependencies: @@ -1196,13 +1111,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-option@npm:7.25.9" - checksum: 10c0/27fb195d14c7dcb07f14e58fe77c44eea19a6a40a74472ec05c441478fa0bb49fa1c32b2d64be7a38870ee48ef6601bdebe98d512f0253aea0b39756c4014f3e - languageName: node - linkType: hard - "@babel/helper-wrap-function@npm:^7.25.7": version: 7.25.7 resolution: "@babel/helper-wrap-function@npm:7.25.7" @@ -1513,18 +1421,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.26.0 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/e594c185b12bfe0bbe7ca78dfeebe870e6d569a12128cac86f3164a075fe0ff70e25ddbd97fd0782906b91f65560c9dc6957716b7b4a68aba2516c9b7455e352 - languageName: node - linkType: hard - -"@babel/plugin-syntax-import-attributes@npm:^7.25.7": +"@babel/plugin-syntax-import-attributes@npm:^7.24.7, @babel/plugin-syntax-import-attributes@npm:^7.25.7": version: 7.25.7 resolution: "@babel/plugin-syntax-import-attributes@npm:7.25.7" dependencies: @@ -2187,18 +2084,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.16.0": - version: 7.25.9 - resolution: "@babel/plugin-transform-react-display-name@npm:7.25.9" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.25.9" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/63a0f962d64e71baf87c212755419e25c637d2d95ea6fdc067df26b91e606ae186442ae815b99a577eca9bf5404d9577ecad218a3cf42d0e9e286ca7b003a992 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-display-name@npm:^7.25.7": +"@babel/plugin-transform-react-display-name@npm:^7.16.0, @babel/plugin-transform-react-display-name@npm:^7.25.7": version: 7.25.7 resolution: "@babel/plugin-transform-react-display-name@npm:7.25.7" dependencies: @@ -10544,7 +10430,6 @@ __metadata: immutable: "npm:^5.0.0" jest: "npm:^29.7.0" jest-extended: "npm:^4.0.2" - jest-fetch-mock: "npm:^3.0.3" jest-watch-typeahead: "npm:^2.2.2" jose: "npm:^4.15.9" lexical: "npm:^0.18.0" @@ -10754,6 +10639,7 @@ __metadata: "@zerologementvacant/schemas": "workspace:*" "@zerologementvacant/utils": "workspace:*" async: "npm:^3.2.6" + axios: "npm:^1.7.7" bcryptjs: "npm:^2.4.3" cli-progress: "npm:^3.12.0" commander: "npm:^12.1.0" @@ -10780,7 +10666,6 @@ __metadata: immutable: "npm:^5.0.0" jest: "npm:^29.7.0" jest-extended: "npm:^4.0.2" - jest-fetch-mock: "npm:^3.0.3" jest-sorted: "npm:^1.0.15" joi: "npm:^17.13.3" jsonlines: "npm:^0.1.1" @@ -10791,7 +10676,6 @@ __metadata: multer: "npm:^1.4.5-lts.1" multer-s3: "npm:^3.0.1" nock: "npm:^13.5.5" - node-fetch: "npm:^3.3.2" nodemailer: "npm:^6.9.15" nodemailer-mock: "npm:^2.0.6" nodemon: "npm:^3.1.7" @@ -13664,15 +13548,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^3.0.4": - version: 3.1.8 - resolution: "cross-fetch@npm:3.1.8" - dependencies: - node-fetch: "npm:^2.6.12" - checksum: 10c0/4c5e022ffe6abdf380faa6e2373c0c4ed7ef75e105c95c972b6f627c3f083170b6886f19fb488a7fa93971f4f69dcc890f122b0d97f0bf5f41ca1d9a8f58c8af - languageName: node - linkType: hard - "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -14153,13 +14028,6 @@ __metadata: languageName: node linkType: hard -"data-uri-to-buffer@npm:^4.0.0": - version: 4.0.1 - resolution: "data-uri-to-buffer@npm:4.0.1" - checksum: 10c0/20a6b93107597530d71d4cb285acee17f66bcdfc03fd81040921a81252f19db27588d87fc8fc69e1950c55cfb0bf8ae40d0e5e21d907230813eb5d5a7f9eb45b - languageName: node - linkType: hard - "data-uri-to-buffer@npm:^6.0.2": version: 6.0.2 resolution: "data-uri-to-buffer@npm:6.0.2" @@ -16447,16 +16315,6 @@ __metadata: languageName: node linkType: hard -"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": - version: 3.2.0 - resolution: "fetch-blob@npm:3.2.0" - dependencies: - node-domexception: "npm:^1.0.0" - web-streams-polyfill: "npm:^3.0.3" - checksum: 10c0/60054bf47bfa10fb0ba6cb7742acec2f37c1f56344f79a70bb8b1c48d77675927c720ff3191fa546410a0442c998d27ab05e9144c32d530d8a52fbe68f843b69 - languageName: node - linkType: hard - "fetch-intercept@npm:^2.4.0": version: 2.4.0 resolution: "fetch-intercept@npm:2.4.0" @@ -16788,15 +16646,6 @@ __metadata: languageName: node linkType: hard -"formdata-polyfill@npm:^4.0.10": - version: 4.0.10 - resolution: "formdata-polyfill@npm:4.0.10" - dependencies: - fetch-blob: "npm:^3.1.2" - checksum: 10c0/5392ec484f9ce0d5e0d52fb5a78e7486637d516179b0eb84d81389d7eccf9ca2f663079da56f761355c0a65792810e3b345dc24db9a8bbbcf24ef3c8c88570c6 - languageName: node - linkType: hard - "formidable@npm:^2.1.2": version: 2.1.2 resolution: "formidable@npm:2.1.2" @@ -19404,16 +19253,6 @@ __metadata: languageName: node linkType: hard -"jest-fetch-mock@npm:^3.0.3": - version: 3.0.3 - resolution: "jest-fetch-mock@npm:3.0.3" - dependencies: - cross-fetch: "npm:^3.0.4" - promise-polyfill: "npm:^8.1.3" - checksum: 10c0/21ffe8c902ca5adafa7ed61760e100e4c290e99b0b487645f5bb92938ea64c2d1d9dc8af46e65fb7917d6237586067d53af756583a77330dbb4fbda079a63c29 - languageName: node - linkType: hard - "jest-get-type@npm:^27.5.1": version: 27.5.1 resolution: "jest-get-type@npm:27.5.1" @@ -22278,13 +22117,6 @@ __metadata: languageName: node linkType: hard -"node-domexception@npm:^1.0.0": - version: 1.0.0 - resolution: "node-domexception@npm:1.0.0" - checksum: 10c0/5e5d63cda29856402df9472335af4bb13875e1927ad3be861dc5ebde38917aecbf9ae337923777af52a48c426b70148815e890a5d72760f1b4d758cc671b1a2b - languageName: node - linkType: hard - "node-fetch@npm:2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -22299,7 +22131,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.7": +"node-fetch@npm:^2.6.7": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -22313,17 +22145,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^3.3.2": - version: 3.3.2 - resolution: "node-fetch@npm:3.3.2" - dependencies: - data-uri-to-buffer: "npm:^4.0.0" - fetch-blob: "npm:^3.1.4" - formdata-polyfill: "npm:^4.0.10" - checksum: 10c0/f3d5e56190562221398c9f5750198b34cf6113aa304e34ee97c94fd300ec578b25b2c2906edba922050fce983338fde0d5d34fcb0fc3336ade5bd0e429ad7538 - languageName: node - linkType: hard - "node-forge@npm:^1": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -25298,13 +25119,6 @@ __metadata: languageName: node linkType: hard -"promise-polyfill@npm:^8.1.3": - version: 8.3.0 - resolution: "promise-polyfill@npm:8.3.0" - checksum: 10c0/97141f07a31a6be135ec9ed53700a3423a771cabec0ba5e08fcb2bf8cfda855479ff70e444fceb938f560be42b450cd032c14f4a940ed2ad1e5b4dcb78368dce - languageName: node - linkType: hard - "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -29907,13 +29721,6 @@ __metadata: languageName: node linkType: hard -"web-streams-polyfill@npm:^3.0.3": - version: 3.3.3 - resolution: "web-streams-polyfill@npm:3.3.3" - checksum: 10c0/64e855c47f6c8330b5436147db1c75cb7e7474d924166800e8e2aab5eb6c76aac4981a84261dd2982b3e754490900b99791c80ae1407a9fa0dcff74f82ea3a7f - languageName: node - linkType: hard - "web-vitals@npm:^1.1.2": version: 1.1.2 resolution: "web-vitals@npm:1.1.2"