From 91a0ab82eaaa0b5967e6ef52d0fc5354870d434f Mon Sep 17 00:00:00 2001 From: robbond Date: Mon, 23 Mar 2026 18:09:36 +0000 Subject: [PATCH] TASK22224: big parity bundle for completion message routes --- .../file/createappealcompletemessage_api.js | 175 +++++++++--------- .../api/file/createrepcompletemessage_api.js | 58 +++--- .../api/file/getawaitingsubmissionfromblob.js | 14 +- tests/phase21/file-handler-contract.test.cjs | 62 +++++++ 4 files changed, 200 insertions(+), 109 deletions(-) diff --git a/pages/api/file/createappealcompletemessage_api.js b/pages/api/file/createappealcompletemessage_api.js index 7b211519..23455b6b 100644 --- a/pages/api/file/createappealcompletemessage_api.js +++ b/pages/api/file/createappealcompletemessage_api.js @@ -18,10 +18,10 @@ const ApiProxy = nextConnect(); ApiProxy.use(middleware); ApiProxy.get(async (req, res) => { - var containerName = req.query.container; - var tempCaseRef = req.query.tempcaseref; - var typeofinvolvement = req.query.inv; - var checkHash = req.query.hash; + const containerName = req.query.container; + const tempCaseRef = req.query.tempcaseref; + const typeofinvolvement = req.query.inv; + const checkHash = req.query.hash; if ( typeof containerName === "undefined" || @@ -38,13 +38,22 @@ ApiProxy.get(async (req, res) => { }); } - var checkquerypath = + const hashCandidatePaths = [ "/api/file/createappealcompletemessage_api?container=" + - containerName + - "&tempcaseref=" + - tempCaseRef; + containerName + + "&tempcaseref=" + + tempCaseRef, + "/api/file/createappealcompletemessage_api?container=" + + encodeURIComponent(containerName) + + "&tempcaseref=" + + encodeURIComponent(tempCaseRef) + ]; - if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) { + const isHashValid = hashCandidatePaths.some( + (candidatePath) => hashAPIPath(candidatePath) == "&hash=" + checkHash + ); + + if (!isHashValid) { return respondError(res, { status: 400, code: "INVALID_HASH", @@ -52,83 +61,83 @@ ApiProxy.get(async (req, res) => { }); } - const blobProgress = await getProgressBlobs( - containerName, - tempCaseRef - ).then((data) => { - return downloadProgressFile(containerName, data.path, tempCaseRef); - }); + try { + const progressBlob = await getProgressBlobs(containerName, tempCaseRef); + const blobProgress = await downloadProgressFile( + containerName, + progressBlob.path, + tempCaseRef + ); - const caseObj = await downloadProgressFile( - containerName, - tempCaseRef + "/" + tempCaseRef + "_case.json", - tempCaseRef - ); + const caseObj = await downloadProgressFile( + containerName, + tempCaseRef + "/" + tempCaseRef + "_case.json", + tempCaseRef + ); - Object.assign(blobProgress, { - "appealComplete": tempCaseRef - }); - - delete blobProgress["pinswg_name"]; - - await createBlob(JSON.stringify(blobProgress), containerName, tempCaseRef) - .then(() => { - //update case.json with lpa ref and description - - let combinedAddress = - blobProgress.pinswg_siteaddressline1 + - (!_.isEmpty(blobProgress.pinswg_siteaddressline2) - ? ", " + blobProgress.pinswg_siteaddressline2 - : "") + - (!_.isEmpty(blobProgress.pinswg_siteaddresstown) - ? ", " + blobProgress.pinswg_siteaddresstown - : ""); - - combinedAddress = - combinedAddress + - ", " + - blobProgress.pinswg_siteaddresscounty + - ", " + - blobProgress.pinswg_siteaddresspostcode; - - Object.assign(caseObj, { - "pinswg_lpareference": - blobProgress.pinswg_lpaapplicationreference, - "description": blobProgress.pinswg_developmentdescription, - "pinswg_caseaddress": combinedAddress - }); - - //send update case.json and then create queue message - getCaseBlob(containerName, tempCaseRef, caseObj).then(() => { - let contactId = caseObj["customerid_contact@odata.bind"]; - contactId = contactId.match(/\(([^)]+)\)/); - - if (typeofinvolvement != 846040000) { - updateAccount( - contactId[1], - { - "pinswg_typeofinvolvement": 846040001 - }, - true - ).catch((error) => { - consoleLogger(error); - }); - } - - createCaseCompleteMessage(containerName, tempCaseRef); - return respondSuccess(res, { - status: "success" - }); - }); - }) - .catch((error) => { - consoleLogger(error); - return respondError(res, { - status: 400, - code: "CREATE_APPEAL_COMPLETE_MESSAGE_FAILED", - message: "Failed to create appeal complete message" - }); + Object.assign(blobProgress, { + appealComplete: tempCaseRef }); + + delete blobProgress.pinswg_name; + + await createBlob( + JSON.stringify(blobProgress), + containerName, + tempCaseRef + ); + + let combinedAddress = + blobProgress.pinswg_siteaddressline1 + + (!_.isEmpty(blobProgress.pinswg_siteaddressline2) + ? ", " + blobProgress.pinswg_siteaddressline2 + : "") + + (!_.isEmpty(blobProgress.pinswg_siteaddresstown) + ? ", " + blobProgress.pinswg_siteaddresstown + : ""); + + combinedAddress = + combinedAddress + + ", " + + blobProgress.pinswg_siteaddresscounty + + ", " + + blobProgress.pinswg_siteaddresspostcode; + + Object.assign(caseObj, { + pinswg_lpareference: blobProgress.pinswg_lpaapplicationreference, + description: blobProgress.pinswg_developmentdescription, + pinswg_caseaddress: combinedAddress + }); + + await getCaseBlob(containerName, tempCaseRef, caseObj); + + let contactId = caseObj["customerid_contact@odata.bind"]; + contactId = contactId.match(/\(([^)]+)\)/); + + if (typeofinvolvement != 846040000) { + updateAccount( + contactId[1], + { + pinswg_typeofinvolvement: 846040001 + }, + true + ).catch((error) => { + consoleLogger(error); + }); + } + + await createCaseCompleteMessage(containerName, tempCaseRef); + return respondSuccess(res, { + status: "success" + }); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "CREATE_APPEAL_COMPLETE_MESSAGE_FAILED", + message: "Failed to create appeal complete message" + }); + } }); export const config = { diff --git a/pages/api/file/createrepcompletemessage_api.js b/pages/api/file/createrepcompletemessage_api.js index d682d651..bff12c91 100644 --- a/pages/api/file/createrepcompletemessage_api.js +++ b/pages/api/file/createrepcompletemessage_api.js @@ -13,10 +13,10 @@ const ApiProxy = nextConnect(); ApiProxy.use(middleware); ApiProxy.get(async (req, res) => { - var containerName = req.query.container; - var tempCaseRef = req.query.tempcaseref; - var filename = req.query.repid; - var checkHash = req.query.hash; + const containerName = req.query.container; + const tempCaseRef = req.query.tempcaseref; + const filename = req.query.repid; + const checkHash = req.query.hash; if ( typeof containerName === "undefined" || @@ -35,15 +35,26 @@ ApiProxy.get(async (req, res) => { }); } - var checkquerypath = + const hashCandidatePaths = [ "/api/file/createrepcompletemessage_api?container=" + - containerName + - "&tempcaseref=" + - tempCaseRef + - "&repid=" + - filename; + containerName + + "&tempcaseref=" + + tempCaseRef + + "&repid=" + + filename, + "/api/file/createrepcompletemessage_api?container=" + + encodeURIComponent(containerName) + + "&tempcaseref=" + + encodeURIComponent(tempCaseRef) + + "&repid=" + + encodeURIComponent(filename) + ]; - if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) { + const isHashValid = hashCandidatePaths.some( + (candidatePath) => hashAPIPath(candidatePath) == "&hash=" + checkHash + ); + + if (!isHashValid) { return respondError(res, { status: 400, code: "INVALID_HASH", @@ -51,18 +62,21 @@ ApiProxy.get(async (req, res) => { }); } - await createRepCompleteMessage(containerName, tempCaseRef, filename) - .then((data) => { - return respondSuccess(res, data); - }) - .catch((error) => { - consoleLogger(error); - return respondError(res, { - status: 400, - code: "CREATE_REP_COMPLETE_MESSAGE_FAILED", - message: "Failed to create representation complete message" - }); + try { + const data = await createRepCompleteMessage( + containerName, + tempCaseRef, + filename + ); + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "CREATE_REP_COMPLETE_MESSAGE_FAILED", + message: "Failed to create representation complete message" }); + } }); export const config = { diff --git a/pages/api/file/getawaitingsubmissionfromblob.js b/pages/api/file/getawaitingsubmissionfromblob.js index 085a8754..8ee749a7 100644 --- a/pages/api/file/getawaitingsubmissionfromblob.js +++ b/pages/api/file/getawaitingsubmissionfromblob.js @@ -2,7 +2,6 @@ import { downloadAllProgressFiles, getAllProgressBlobs } from "../../../actions/azurestorage"; -import _ from "lodash"; import nextConnect from "next-connect"; import middleware from "../middleware/middleware"; import { hashAPIPath } from "../../../actions/core/hash"; @@ -28,10 +27,17 @@ ApiProxy.get(async (req, res) => { }); } - const checkquerypath = - "/api/file/getawaitingsubmissionfromblob?container=" + containerName; + const hashCandidatePaths = [ + "/api/file/getawaitingsubmissionfromblob?container=" + containerName, + "/api/file/getawaitingsubmissionfromblob?container=" + + encodeURIComponent(containerName) + ]; - if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) { + const isHashValid = hashCandidatePaths.some( + (candidatePath) => hashAPIPath(candidatePath) == "&hash=" + checkHash + ); + + if (!isHashValid) { return respondError(res, { status: 400, code: "INVALID_HASH", diff --git a/tests/phase21/file-handler-contract.test.cjs b/tests/phase21/file-handler-contract.test.cjs index d9520adf..26fa896e 100644 --- a/tests/phase21/file-handler-contract.test.cjs +++ b/tests/phase21/file-handler-contract.test.cjs @@ -485,6 +485,68 @@ test("uploadsinglefile handler dependency failure returns UPLOAD_SINGLE_FILE_FAI ); }); +test("createrepcompletemessage handler accepts encoded hash variant", async () => { + const mod = loadModule("pages/api/file/createrepcompletemessage_api.js", { + nextConnect: createNextConnectMock(), + middleware: () => {}, + hashAPIPath: (queryPath) => + queryPath.includes("repid=rep%201") + ? "&hash=expected" + : "&hash=other", + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + consoleLogger: () => {}, + createRepCompleteMessage: async () => ({ ok: true }) + }); + + const req = { + query: { + container: "c1", + tempcaseref: "TMP/1", + repid: "rep 1", + hash: "expected" + } + }; + const res = createRes(); + await mod.default.handler(req, res); + + assert.strictEqual(res.state.statusCode, 200); + assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), { + ok: true + }); +}); + +test("createrepcompletemessage handler dependency failure returns CREATE_REP_COMPLETE_MESSAGE_FAILED", async () => { + const mod = loadModule("pages/api/file/createrepcompletemessage_api.js", { + nextConnect: createNextConnectMock(), + middleware: () => {}, + hashAPIPath: () => "&hash=expected", + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + consoleLogger: () => {}, + createRepCompleteMessage: async () => { + throw new Error("rep message failed"); + } + }); + + const req = { + query: { + container: "c1", + tempcaseref: "TMP1", + repid: "rep1", + hash: "expected" + } + }; + const res = createRes(); + await mod.default.handler(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "CREATE_REP_COMPLETE_MESSAGE_FAILED" + ); +}); + test("getawaitingsubmissionfromblob handler success returns payload", async () => { const mod = loadModule("pages/api/file/getawaitingsubmissionfromblob.js", { nextConnect: createNextConnectMock(),