Skip to content

Commit

Permalink
Merge pull request #97 from BaseAdresseNationale/antoineludeau/add-ch…
Browse files Browse the repository at this point in the history
…eck-rules-for-districtID-consistency

Added check rules for district ID consistency and rights
  • Loading branch information
antoineludeau authored Sep 4, 2024
2 parents 0d36f6e + 084d773 commit be709e2
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`balTopoToBanTopo > Should return false as bal does not use ban IDs 1`] = `false`;

exports[`balTopoToBanTopo > Should return true as bal 1.3 uses ban IDs 1`] = `true`;

exports[`balTopoToBanTopo > Should return true as bal 1.4 uses ban IDs 1`] = `true`;
2 changes: 1 addition & 1 deletion src/bal-converter/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ export { default as balJSONlegacy2balJSON } from "./bal-json-legacy-to-bal-json.
export { default as convertBalPositionTypeToBanPositionType } from "./bal-position-type-to-ban-position-type.js";
export { default as balToBan } from "./bal-to-ban.js";
export { default as balTopoToBanTopo } from "./bal-topo-to-ban-topo.js";
export { default as checkIfBALUseBanId } from "./check-if-bal-use-ban-id.js";
export { default as csvBalToJsonBal } from "./csv-bal-to-json-bal.js";
export { default as digestIDsFromBalAddr } from "./digest-ids-from-bal-addr.js";
export { default as digestIDsFromBalUIDs } from "./digest-ids-from-bal-uids.js";
export { default as jsonBalToCsvBal } from "./json-bal-to-csv-bal.js";
export { default as getBalVersion } from "./get-bal-version.js";
export { default as validator } from "./validator.js";
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import fs from "node:fs";
import { describe, expect, test } from "vitest";
import { checkIfBALUseBanId } from "./index.js";
import { validator } from "./index.js";

const pathToMockBalJSONlegacy =
"./data-mock/adresses-21286_cocorico.legacy.json";
const mockBalJSONlegacyStr = fs.readFileSync(pathToMockBalJSONlegacy, "utf8");
const balJSONlegacy = JSON.parse(mockBalJSONlegacyStr);

const districtID = 'e2b5c142-3eb3-4d07-830a-3d1a59195dfd'

const pathToMockBalJSON_1 = "./data-mock/adresses-21286_cocorico.json";
const mockBalJSONStr_1 = fs.readFileSync(pathToMockBalJSON_1, "utf8");
const balJSON_1 = JSON.parse(mockBalJSONStr_1);
Expand Down Expand Up @@ -60,40 +62,69 @@ const balJSONSimplifiedAndModified_4 = [
},
]

const balWithMultipleDistrictIDs = [
{
...balJSON_2[0],
},
{
...balJSON_2[1],
id_ban_commune: "1234",
},
]

const balWithDifferentDistrictID = [
{
...balJSON_2[0],
id_ban_commune: "1234",
},
]

describe("balTopoToBanTopo", () => {
test("Should return true as bal 1.3 uses ban IDs", async () => {
expect(checkIfBALUseBanId(balJSON_1)).toMatchSnapshot();
expect(await validator(districtID, balJSON_1, '1.3')).toMatchSnapshot();
});

test("Should return true as bal 1.4 uses ban IDs", async () => {
expect(checkIfBALUseBanId(balJSON_2)).toMatchSnapshot();
expect(await validator(districtID, balJSON_2, '1.4')).toMatchSnapshot();
});

test("Should return false as bal does not use ban IDs", async () => {
expect(checkIfBALUseBanId(balJSONlegacy)).toMatchSnapshot();
expect(await validator(districtID, balJSONlegacy, '1.3')).toMatchSnapshot();
});

test("Should throw an error as bal does not have a district ID on one of its line", async () => {
expect(() =>
checkIfBALUseBanId(balJSONSimplifiedAndModified_1)
).toThrowError(/Missing districtID/);
await expect(
validator(districtID, balJSONSimplifiedAndModified_1, '1.3')
).rejects.toThrowError(/Missing districtID/);
});

test("Should throw an error as bal does not have a common toponym ID on one of its line", async () => {
expect(() =>
checkIfBALUseBanId(balJSONSimplifiedAndModified_2)
).toThrowError(/Missing mainTopoID/);
await expect(
validator(districtID, balJSONSimplifiedAndModified_2, '1.3')
).rejects.toThrowError(/Missing mainTopoID/);
});

test("Should throw an error as bal does not have an address ID on one of its line that has a number different from the topo number", async () => {
expect(() =>
checkIfBALUseBanId(balJSONSimplifiedAndModified_3)
).toThrowError(/Missing addressID/);
await expect(
validator(districtID, balJSONSimplifiedAndModified_3, '1.3')
).rejects.toThrowError(/Missing addressID/);
});

test ("Should throw an error as some lines are using BanIDs and some are not", async () => {
expect(() =>
checkIfBALUseBanId(balJSONSimplifiedAndModified_4)
).toThrowError(/Some lines are using BanIDs and some are not/);
test("Should throw an error as some lines are using BanIDs and some are not", async () => {
await expect(
validator(districtID, balJSONSimplifiedAndModified_4, '1.3')
).rejects.toThrowError(/Some lines are using BanIDs and some are not/);
})

test("Should throw an error as multiple district IDs", async () => {
await expect(
validator(districtID, balWithMultipleDistrictIDs, '1.4')
).rejects.toThrowError(/Multiple district IDs/);
})

test("Should throw an error as district ID from BAL different from district ID from district DB", async () => {
await expect(
validator(districtID, balWithDifferentDistrictID, '1.4')
).rejects.toThrowError(/Missing rights/);
})
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Bal, BalVersion } from "../../types/bal-types.js";
import { Bal, BalVersion } from "../../types/bal-types";
import { logger } from "../../utils/logger.js";
import { digestIDsFromBalAddr } from "./index.js";
import { numberForTopo as IS_TOPO_NB } from "../bal-converter.config.js";

const checkIfBALUseBanId = (bal: Bal, version?: BalVersion) => {
const validator = async (districtID: string, bal: Bal, version: BalVersion) => {
let balAdresseUseBanId = 0
let balAddressDoNotUseBanId = 0
const districtIDs = new Set();
for (const balAdresse of bal) {
// Check presence and format of BanIDs
const { districtID, mainTopoID, addressID } = digestIDsFromBalAddr(
balAdresse,
version
Expand All @@ -15,33 +17,38 @@ const checkIfBALUseBanId = (bal: Bal, version?: BalVersion) => {
// If at least one of the IDs is present, it means that the BAL address is using BanID
if (districtID || mainTopoID || addressID) {
if (!districtID){
logger.info(`Missing districtID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing districtID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing districtID - bal address ${JSON.stringify(balAdresse)}`);
}

if (!mainTopoID){
logger.info(`Missing mainTopoID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing mainTopoID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing mainTopoID - bal address ${JSON.stringify(balAdresse)}`);
}

if (balAdresse.numero !== Number(IS_TOPO_NB) && !addressID){
logger.info(`Missing addressID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing addressID for bal address ${JSON.stringify(balAdresse)}`);
throw new Error(`Missing addressID - bal address ${JSON.stringify(balAdresse)}`);
}
balAdresseUseBanId++
districtIDs.add(districtID);
} else {
balAddressDoNotUseBanId++
}
}

if (balAdresseUseBanId === bal.length){
// Check district IDs consistency
if (districtIDs.size > 1){
throw new Error(`Multiple district IDs - ${JSON.stringify([...districtIDs])}`);
}
if (!districtIDs.has(districtID)){
throw new Error(`Missing rights - District ID ${districtID} cannot be updated`);
}
return true;
} else if (balAddressDoNotUseBanId === bal.length){
return false;
} else {
logger.info(`Some lines are using BanIDs and some are not`);
throw new Error(`Some lines are using BanIDs and some are not`);
}
};
}

export default checkIfBALUseBanId;
export default validator;
62 changes: 35 additions & 27 deletions src/compute-from-cog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@ import {
getRevisionFileText,
} from "./dump-api/index.js";
import { sendBalToBan } from "./bal-converter/index.js";
import { getDistrictFromCOG, partialUpdateDistricts, sendBalToLegacyCompose } from "./ban-api/index.js";
import {
checkIfBALUseBanId,
getDistrictFromCOG,
partialUpdateDistricts,
sendBalToLegacyCompose,
} from "./ban-api/index.js";
import {
validator,
csvBalToJsonBal,
getBalVersion,
} from "./bal-converter/helpers/index.js";

import acceptedCogList from "./accepted-cog-list.json" assert { type: "json" };

export const computeFromCog = async (cog: string, forceLegacyCompose: string) => {

export const computeFromCog = async (
cog: string,
forceLegacyCompose: string
) => {
// Temporary check for testing purpose
// Check if cog is part of the accepted cog list
const isCogAccepted = acceptedCogList.includes(cog);

if (!isCogAccepted){
logger.info(`District cog ${cog} is not part of the whitelist: sending BAL to legacy compose...`)
return await sendBalToLegacyCompose(cog, forceLegacyCompose as string)
if (!isCogAccepted) {
logger.info(
`District cog ${cog} is not part of the whitelist: sending BAL to legacy compose...`
);
return await sendBalToLegacyCompose(cog, forceLegacyCompose as string);
}

logger.info(`District cog ${cog} is part of the whitelist.`)
logger.info(`District cog ${cog} is part of the whitelist.`);

const revision = await getRevisionFromDistrictCOG(cog);
const revisionFileText = await getRevisionFileText(revision._id);
Expand All @@ -37,29 +45,29 @@ export const computeFromCog = async (cog: string, forceLegacyCompose: string) =>
const version = getBalVersion(bal);
logger.info(`District cog ${cog} is using BAL version ${version}`);

const districtResponseRaw = await getDistrictFromCOG(cog);
if (!districtResponseRaw.length) {
throw new Error(`No district found with cog ${cog}`);
} else if (districtResponseRaw.length > 1) {
throw new Error(
`Multiple district found with cog ${cog}. Behavior not handled yet.`
);
}

const { id } = districtResponseRaw[0];

// Check if bal is using BanID
// If not, send process to ban-plateforme legacy API
// If the use of IDs is partial, throwing an error
const useBanId = await checkIfBALUseBanId(bal, version);
const useBanId = await validator(id, bal, version);

if (!useBanId) {
logger.info(`District cog ${cog} does not use BanID: sending BAL to legacy compose...`)
return await sendBalToLegacyCompose(cog, forceLegacyCompose as string)
logger.info(
`District cog ${cog} does not use BanID: sending BAL to legacy compose...`
);
return await sendBalToLegacyCompose(cog, forceLegacyCompose as string);
} else {
logger.info(`District cog ${cog} is using banID`);
// Update District with revision data
const districtResponseRaw = await getDistrictFromCOG(cog);
if (!districtResponseRaw.length) {
throw new Error(`No district found with cog ${cog}`);
} else if (districtResponseRaw.length > 1) {
throw new Error(
`Multiple district found with cog ${cog}. Behavior not handled yet.`
);
}

const { id } = districtResponseRaw[0];
logger.info(`District with cog ${cog} found (id: ${id})`);

// Update District meta with revision data from dump-api (id and date)
const districtUpdate = {
id,
Expand All @@ -75,7 +83,7 @@ export const computeFromCog = async (cog: string, forceLegacyCompose: string) =>
const result = (await sendBalToBan(bal)) || {};

if (!Object.keys(result).length) {
const response = `District id ${id} not updated in BAN BDD. No changes detected.`
const response = `District id ${id} not updated in BAN BDD. No changes detected.`;
logger.info(response);
return response;
}
Expand All @@ -85,7 +93,7 @@ export const computeFromCog = async (cog: string, forceLegacyCompose: string) =>
result
)}`
);

return result;
}
}
};

0 comments on commit be709e2

Please sign in to comment.