From 4f001b012618c96c1b48da9ac996e9105049ef16 Mon Sep 17 00:00:00 2001 From: antoineludeau <52679050+antoineludeau@users.noreply.github.com> Date: Tue, 7 Nov 2023 17:48:51 +0100 Subject: [PATCH] Added validation context to handle patch --- lib/api/address/schema.js | 47 ++++++++++++++++++-------------- lib/api/address/utils.js | 22 ++------------- lib/api/common-toponym/schema.js | 26 ++++++++++-------- lib/api/common-toponym/utils.js | 14 ++-------- lib/api/district/schema.js | 39 ++++++++++++++++---------- lib/api/district/utils.js | 4 +-- lib/api/helper.js | 8 +++--- lib/api/schema.js | 4 --- 8 files changed, 76 insertions(+), 88 deletions(-) diff --git a/lib/api/address/schema.js b/lib/api/address/schema.js index ffd097d4..a52d4817 100644 --- a/lib/api/address/schema.js +++ b/lib/api/address/schema.js @@ -15,29 +15,36 @@ const metaSchema = object({ export const banAddressSchema = object({ id: banID.required(), - mainCommonToponymID: banID.required(), + mainCommonToponymID: banID.when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), secondaryCommonToponymIDs: array().of(banID), - districtID: banID.required(), - number: number().positive().integer().required(), + districtID: banID.when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), + number: number().positive().integer().when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), suffix: string().trim(), - labels: array().of(labelSchema), + labels: array().of(labelSchema).when('$isPatch', { + is: true, + // eslint-disable-next-line unicorn/no-thenable + then: schema => schema.default(null).nullable(), + }), certified: boolean(), - positions: array().of(positionSchema).required(), - updateDate: date().required(), - meta: metaSchema -}).noUnknown() - -export const banAddressSchemaForPatch = object({ - id: banID.required(), - mainCommonToponymID: banID, - secondaryCommonToponymIDs: array().of(banID), - districtID: banID, - number: number().positive().integer(), - suffix: string().trim(), - labels: array().of(labelSchema).default(null).nullable(), - certified: boolean().default(false), - positions: array().of(positionSchema).default(null).nullable(), - updateDate: date(), + positions: array().of(positionSchema).when('$isPatch', { + is: true, + // eslint-disable-next-line unicorn/no-thenable + then: schema => schema.default(null).nullable(), + otherwise: schema => schema.required(), + }), + updateDate: date().when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), meta: metaSchema }).noUnknown() diff --git a/lib/api/address/utils.js b/lib/api/address/utils.js index 35b1e3b5..a21ad460 100644 --- a/lib/api/address/utils.js +++ b/lib/api/address/utils.js @@ -1,7 +1,7 @@ import {checkDataFormat, dataValidationReportFrom, checkIdsIsUniq, checkIdsIsVacant, checkIdsIsAvailable, checkDataShema, checkIdsShema, checkIfCommonToponymsExist, checkIfDistrictsExist} from '../helper.js' import {banID} from '../schema.js' import {getAddresses, getAllAddressIDsFromDistrict, getAllAddressIDsOutsideDistrict} from './models.js' -import {banAddressSchema, banAddressSchemaForPatch} from './schema.js' +import {banAddressSchema} from './schema.js' const getExistingAddressIDs = async addressIDs => { const existingAddresses = await getAddresses(addressIDs) @@ -50,24 +50,6 @@ export const checkAddressesRequest = async (addresses, actionType) => { switch (actionType) { case 'insert': case 'update': - report = checkDataFormat( - `The request require an Array of address but receive ${typeof addresses}`, - 'No address send to job', - addresses - ) - || await checkAddressesIDsRequest(addresses.map(address => address.id), actionType, false) - || await checkDataShema('Invalid format', addresses, banAddressSchema) - || await checkIfCommonToponymsExist(addresses.reduce((acc, {mainCommonToponymID, secondaryCommonToponymIDs}) => { - const ids = [mainCommonToponymID] - if (secondaryCommonToponymIDs) { - ids.push(...secondaryCommonToponymIDs) - } - - return [...acc, ...ids] - }, [])) - || await checkIfDistrictsExist(addresses.map(({districtID}) => districtID)) - || dataValidationReportFrom(true) - break case 'patch': report = checkDataFormat( `The request require an Array of address but receive ${typeof addresses}`, @@ -75,7 +57,7 @@ export const checkAddressesRequest = async (addresses, actionType) => { addresses ) || await checkAddressesIDsRequest(addresses.map(address => address.id), actionType, false) - || await checkDataShema('Invalid format', addresses, banAddressSchemaForPatch) + || await checkDataShema('Invalid format', addresses, banAddressSchema, {isPatch: actionType === 'patch'}) || await checkIfCommonToponymsExist(addresses.reduce((acc, {mainCommonToponymID, secondaryCommonToponymIDs}) => { const ids = mainCommonToponymID ? [mainCommonToponymID] : [] if (secondaryCommonToponymIDs) { diff --git a/lib/api/common-toponym/schema.js b/lib/api/common-toponym/schema.js index c039eb4e..451e2178 100644 --- a/lib/api/common-toponym/schema.js +++ b/lib/api/common-toponym/schema.js @@ -8,19 +8,21 @@ const metaSchema = object({ export const banCommonToponymSchema = object({ id: banID.required(), - districtID: banID.required(), - labels: array().of(labelSchema).required(), + districtID: banID.when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), + labels: array().of(labelSchema).when('$isPatch', { + is: true, + // eslint-disable-next-line unicorn/no-thenable + then: schema => schema.default(null).nullable(), + otherwise: schema => schema.required(), + }), geometry: geometrySchema.default(null).nullable(), - updateDate: date().required(), - meta: metaSchema -}).noUnknown() - -export const banCommonToponymSchemaForPatch = object({ - id: banID.required(), - districtID: banID, - labels: array().of(labelSchema).default(null).nullable(), - geometry: geometrySchema.default(null).nullable(), - updateDate: date(), + updateDate: date().when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), meta: metaSchema }).noUnknown() diff --git a/lib/api/common-toponym/utils.js b/lib/api/common-toponym/utils.js index 3076ff8b..d088eed9 100644 --- a/lib/api/common-toponym/utils.js +++ b/lib/api/common-toponym/utils.js @@ -1,7 +1,7 @@ import {checkDataFormat, dataValidationReportFrom, checkIdsIsUniq, checkIdsIsVacant, checkIdsIsAvailable, checkDataShema, checkIdsShema, checkIfDistrictsExist} from '../helper.js' import {banID} from '../schema.js' import {getCommonToponyms, getAllCommonToponymIDsFromDistrict, getAllCommonToponymIDsOutsideDistrict} from './models.js' -import {banCommonToponymSchema, banCommonToponymSchemaForPatch} from './schema.js' +import {banCommonToponymSchema} from './schema.js' const getExistingCommonToponymIDs = async commonToponymIDs => { const existingCommonToponyms = await getCommonToponyms(commonToponymIDs) @@ -50,16 +50,6 @@ export const checkCommonToponymsRequest = async (commonToponyms, actionType) => switch (actionType) { case 'insert': case 'update': - report = checkDataFormat( - `The request require an Array of common toponym but receive ${typeof commonToponyms}`, - 'No common toponym send to job', - commonToponyms - ) - || await checkCommonToponymsIDsRequest(commonToponyms.map(commonToponym => commonToponym.id), actionType, false) - || await checkDataShema('Invalid common toponym format', commonToponyms, banCommonToponymSchema) - || await checkIfDistrictsExist(commonToponyms.map(({districtID}) => districtID)) - || dataValidationReportFrom(true) - break case 'patch': report = checkDataFormat( `The request require an Array of common toponym but receive ${typeof commonToponyms}`, @@ -67,7 +57,7 @@ export const checkCommonToponymsRequest = async (commonToponyms, actionType) => commonToponyms ) || await checkCommonToponymsIDsRequest(commonToponyms.map(commonToponym => commonToponym.id), actionType, false) - || await checkDataShema('Invalid common toponym format', commonToponyms, banCommonToponymSchemaForPatch) + || await checkDataShema('Invalid common toponym format', commonToponyms, banCommonToponymSchema, {isPatch: actionType === 'patch'}) || await checkIfDistrictsExist(commonToponyms.reduce((acc, {districtID}) => { if (districtID) { return [...acc, districtID] diff --git a/lib/api/district/schema.js b/lib/api/district/schema.js index 806db9c6..963ed09a 100644 --- a/lib/api/district/schema.js +++ b/lib/api/district/schema.js @@ -1,10 +1,17 @@ -import {object, array, date, bool} from 'yup' -import {banID, labelSchema, inseeSchema, balSchema} from '../schema.js' +import {object, string, array, date, bool} from 'yup' +import {banID, labelSchema, balSchema} from '../schema.js' const configSchema = object({ useBanId: bool() }).noUnknown() +const inseeSchema = object({ + cog: string().trim().length(5).when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), +}) + const metaSchema = object({ insee: inseeSchema, bal: balSchema, @@ -12,19 +19,23 @@ const metaSchema = object({ export const banDistrictSchema = object({ id: banID.required(), - labels: array().of(labelSchema).required(), - updateDate: date().required(), - config: configSchema, - meta: metaSchema -}).noUnknown() - -export const banDistrictSchemaForPatch = object({ - id: banID.required(), - labels: array().of(labelSchema).default(null).nullable(), - updateDate: date(), + labels: array().of(labelSchema).when('$isPatch', { + is: true, + // eslint-disable-next-line unicorn/no-thenable + then: schema => schema.default(null).nullable(), + otherwise: schema => schema.required(), + }), + updateDate: date().when('$isPatch', { + is: true, + otherwise: schema => schema.required(), + }), config: configSchema, - meta: metaSchema.default(null).nullable(), -}).noUnknown() + meta: metaSchema.when('$isPatch', { + is: true, + // eslint-disable-next-line unicorn/no-thenable + then: schema => schema.default(null).nullable(), + }), +}) export const districtDefaultOptionalValues = { config: undefined, diff --git a/lib/api/district/utils.js b/lib/api/district/utils.js index 031ba64e..6e60c5b1 100644 --- a/lib/api/district/utils.js +++ b/lib/api/district/utils.js @@ -1,7 +1,7 @@ import {checkDataFormat, dataValidationReportFrom, checkIdsIsUniq, checkIdsIsVacant, checkIdsIsAvailable, checkDataShema, checkIdsShema} from '../helper.js' import {banID} from '../schema.js' import {getDistricts} from './models.js' -import {banDistrictSchema, banDistrictSchemaForPatch} from './schema.js' +import {banDistrictSchema} from './schema.js' const getExistingDistrictIDs = async districtIDs => { const existingDistricts = await getDistricts(districtIDs) @@ -57,7 +57,7 @@ export const checkDistrictsRequest = async (districts, actionType) => { districts ) || await checkDistrictsIDsRequest(districts.map(district => district.id), actionType, false) - || await checkDataShema('Invalid format', districts, actionType === 'patch' ? banDistrictSchemaForPatch : banDistrictSchema) + || await checkDataShema('Invalid format', districts, banDistrictSchema, {isPatch: actionType === 'patch'}) || dataValidationReportFrom(true) break default: diff --git a/lib/api/helper.js b/lib/api/helper.js index 0c138ca3..cab8ce01 100644 --- a/lib/api/helper.js +++ b/lib/api/helper.js @@ -75,9 +75,9 @@ export const checkIdsShema = async (err = 'Invalid IDs format', ids, schema) => } } -const dataSchemaValidation = async (data, schema) => { +const dataSchemaValidation = async (data, schema, context) => { try { - await schema.validate(data, {strict: true, abortEarly: false}) + await schema.validate(data, {strict: true, abortEarly: false, context}) } catch (error) { return dataValidationReportFrom(false, `Invalid data format (id: ${data.id})`, error.errors) } @@ -85,8 +85,8 @@ const dataSchemaValidation = async (data, schema) => { return dataValidationReportFrom(true) } -export const checkDataShema = async (err = 'Invalid data format', dataArr, schema) => { - const dataArrValidationPromises = dataArr.map(data => dataSchemaValidation(data, schema)) +export const checkDataShema = async (err = 'Invalid data format', dataArr, schema, context) => { + const dataArrValidationPromises = dataArr.map(data => dataSchemaValidation(data, schema, context)) const dataArrValidation = await Promise.all(dataArrValidationPromises) const invalidDataArr = dataArrValidation.filter(({isValid}) => !isValid) if (invalidDataArr.length > 0) { diff --git a/lib/api/schema.js b/lib/api/schema.js index 5b5d350e..fbdd8660 100644 --- a/lib/api/schema.js +++ b/lib/api/schema.js @@ -12,10 +12,6 @@ export const geometrySchema = object({ coordinates: array().length(2).of(number()).required(), }).noUnknown() -export const inseeSchema = object({ - cog: string().trim().length(5).required() -}).noUnknown() - export const cadastreSchema = object({ ids: array().of(string().trim()) }).noUnknown()