From 05f26ff12c3cd2c7d7e626a2e0899204c40ee0db Mon Sep 17 00:00:00 2001 From: robbond Date: Wed, 25 Mar 2026 11:49:19 +0000 Subject: [PATCH] refactor(case): normalize route composition with fileRouteBuilder --- actions/services/caseDirectService.js | 186 ++++++++++++------------ memory-bank/change-log.md | 43 ++++++ tests/phase6/service-behaviour.test.cjs | 24 +++ 3 files changed, 164 insertions(+), 89 deletions(-) diff --git a/actions/services/caseDirectService.js b/actions/services/caseDirectService.js index 47d53138..0b406534 100644 --- a/actions/services/caseDirectService.js +++ b/actions/services/caseDirectService.js @@ -2,45 +2,54 @@ import { BASE_URL } from "../core/env"; import { consoleLogger } from "../core/logger"; import { logAndReturnResponse } from "./httpServiceUtils"; import { getJson, requestJson } from "../clients/endpointClient"; +import { buildFileQuery, withBaseUrl } from "../clients/fileRouteBuilder"; export const getCaseMessage = (searchString) => { - return getJson( - BASE_URL + "/api/endpoint/getcasemessage_api?id=" + searchString - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getcasemessage_api", { + id: searchString + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse); }; export const getIncidentbyID = (searchString) => { - return getJson( - BASE_URL + - "/api/endpoint/getincidentbyid_api?searchString=" + - searchString - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getincidentbyid_api", { + searchString + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse); }; export const getIsPublishedbyID = (searchString) => { - return getJson( - "/api/endpoint/getispublishedbyid_api?searchString=" + searchString - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getispublishedbyid_api", { + searchString + }); + + return getJson(route).catch(logAndReturnResponse); }; export const getPartSavedAppeal = (searchString) => { - return getJson( - BASE_URL + - "/api/endpoint/getpartsavedappeal_api?searchString=" + - searchString - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getpartsavedappeal_api", { + searchString + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse); }; export const getSIPSEvents = async (caseid) => { - return getJson( - BASE_URL + "/api/endpoint/getsipsevents_api?caseid=" + caseid - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getsipsevents_api", { + caseid + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse); }; export const getSIPSMedia = async (caseid) => { - return getJson( - BASE_URL + "/api/endpoint/getsipsmedia_api?caseid=" + caseid - ).catch(logAndReturnResponse); + const route = buildFileQuery("/api/endpoint/getsipsmedia_api", { + caseid + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse); }; export const getAppealID = ( @@ -48,14 +57,13 @@ export const getAppealID = ( updateFormCollection, primaryAttribute ) => { - return getJson( - "/api/endpoint/getappealid_api?updateFormCollection=" + - updateFormCollection + - "&primaryAttribute=" + - primaryAttribute + - "&caseReference=" + - caseReference - ) + const route = buildFileQuery("/api/endpoint/getappealid_api", { + updateFormCollection, + primaryAttribute, + caseReference + }); + + return getJson(route) .then((data) => { const result = Object.entries(data.value[0]).filter( ([key]) => !key.startsWith("_") @@ -79,19 +87,16 @@ export const createNewCase = ( var data = createBody; - var queryUrl = - "/api/endpoint/createcase_api?appealTypeId=" + - appealTypeId + - "&lpaID=" + - lpaID + - "&contactid=" + - contactid + - "&containername=" + - containerName; + var queryUrl = buildFileQuery("/api/endpoint/createcase_api", { + appealTypeId, + lpaID, + contactid, + containername: containerName + }); var config = { method: "post", - url: BASE_URL + queryUrl, + url: withBaseUrl(BASE_URL, queryUrl), data: data }; @@ -115,15 +120,12 @@ export const createNewCaseBlob = ( data.pinswg_lpaname = lpaName; data.createdon = new Date(); - var queryUrl = - "/api/file/createcase_api?appealTypeId=" + - appealTypeId + - "&lpaID=" + - lpaID + - "&contactid=" + - contactid + - "&containername=" + - containerName; + var queryUrl = buildFileQuery("/api/file/createcase_api", { + appealTypeId, + lpaID, + contactid, + containername: containerName + }); var config = { method: "post", @@ -151,11 +153,10 @@ export const updateCase = async ( primaryAttribute ); - var queryUrl = - "/api/endpoint/updatecase_api?updateFormCollection=" + - updateFormCollection + - "&appealObj=" + - appealObj; + var queryUrl = buildFileQuery("/api/endpoint/updatecase_api", { + updateFormCollection, + appealObj + }); var config = { method: "post", @@ -183,11 +184,10 @@ export const updateCaseBlob = async ( primaryAttribute ); - var queryUrl = - "/api/file/updatecase_api?updateFormCollection=" + - updateFormCollection + - "&appealObj=" + - appealObj; + var queryUrl = buildFileQuery("/api/file/updatecase_api", { + updateFormCollection, + appealObj + }); var config = { method: "post", @@ -201,68 +201,76 @@ export const updateCaseBlob = async ( }; export const patchCase = async (incidentid) => { - var queryUrl = "/api/endpoint/patchcase_api?incidentid=" + incidentid; + var queryUrl = buildFileQuery("/api/endpoint/patchcase_api", { + incidentid + }); return getJson(queryUrl).catch((error) => { //console.log("this error:", error); }); }; export const getCase = (incidentID) => { - return getJson( - BASE_URL + "/api/endpoint/getcase_api?incidentID=" + incidentID - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getcase_api", { + incidentID + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getCaseByID = (incidentID) => { - return getJson( - BASE_URL + "/api/endpoint/getcasebyid_api?incidentID=" + incidentID - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getcasebyid_api", { + incidentID + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getAppealPDFDocs = (incidentID) => { - return getJson( - BASE_URL + - "/api/endpoint/getappealpdfdocuments_api?incidentid=" + - incidentID - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", { + incidentid: incidentID + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getAppealPDFDocument = async (incidentid) => { - return getJson( - BASE_URL + - "/api/endpoint/getappealpdfdocuments_api?incidentid=" + - incidentid - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", { + incidentid + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); return error.response; }); }; export const getPortalModuleDetails = async (appealType, caseReference) => { - return getJson( - BASE_URL + - "/api/endpoint/getportalmoduledetails_api?appealType=" + - appealType + - "&caseReference=" + - encodeURI(caseReference) - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getportalmoduledetails_api", { + appealType, + caseReference: encodeURI(caseReference) + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getPortalModuleDetailsProxy = (appealType, caseReference) => { - return getJson( - "/api/endpoint/getportalmoduledetailsproxy_api?appealType=" + - appealType + - "&caseReference=" + - caseReference.replace(/\'/g, "''") - ).catch((error) => { + const route = buildFileQuery( + "/api/endpoint/getportalmoduledetailsproxy_api", + { + appealType, + caseReference: caseReference.replace(/\'/g, "''") + } + ); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index b6e43175..4ccccdb5 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -2559,3 +2559,46 @@ Validation: Follow-ups: - Optional next widened slice: apply the same query-normalization helpers in `caseDirectService` and add dedicated phase22 behavioral assertions for `portalDirectService` route-building/signing composition. + +--- + +### CL-072: TASK22260 next widened cross-module slice — case service query normalization via fileRouteBuilder + +date: 2026-03-25 +author: Cline +scope: `actions/services/caseDirectService.js`, `tests/phase6/service-behaviour.test.cjs` +type: change +rationale: Continue widened cross-module rollout by applying shared query/route composition helpers to `caseDirectService`, reducing repeated string concatenation and aligning route construction style with document/portal services. +impact: Improves maintainability and consistency in case service URL/query composition while preserving existing runtime behavior and error contracts. +status: completed + +Summary: + +- Refactored `actions/services/caseDirectService.js` to use `fileRouteBuilder` helpers: + - `buildFileQuery` + - `withBaseUrl` +- Normalized route composition for read and write helpers, including: + - case retrieval/search flows (`getCaseMessage`, `getIncidentbyID`, `getIsPublishedbyID`, `getPartSavedAppeal`, `getSIPSEvents`, `getSIPSMedia`) + - appeal resolution/update/create flows (`getAppealID`, `createNewCase`, `createNewCaseBlob`, `updateCase`, `updateCaseBlob`, `patchCase`) + - case/detail/document/module reads (`getCase`, `getCaseByID`, `getAppealPDFDocs`, `getAppealPDFDocument`, `getPortalModuleDetails`, `getPortalModuleDetailsProxy`) +- Preserved existing contracts: + - BASE_URL usage patterns where previously applied + - method/payload semantics for `requestJson` paths + - catch-path logging and return behavior (`logAndReturnResponse`, `consoleLogger`, `error.response` paths) +- Expanded phase6 behavioural coverage with a focused assertion for case route composition: + - `case/getPortalModuleDetails composes BASE_URL route with encoded case reference` + +Validation: + +- `node tests/phase6/service-behaviour.test.cjs` -> pass (9/9) +- `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) +- `node tests/phase22/index.test.cjs` -> pass + - core-token: 2/2 + - client-utils: 6/6 + - file-client: 4/4 + - phase22 combined: pass +- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) + +Follow-ups: + +- Optional next widened slice: add a focused phase22 behavioral suite for `caseDirectService` and normalize any remaining specialized encoding usage behind explicit helper options where appropriate. diff --git a/tests/phase6/service-behaviour.test.cjs b/tests/phase6/service-behaviour.test.cjs index 06f49ff6..c869a445 100644 --- a/tests/phase6/service-behaviour.test.cjs +++ b/tests/phase6/service-behaviour.test.cjs @@ -138,6 +138,30 @@ test("case/getCaseMessage returns error.response on failure", async () => { assert.strictEqual(logger.calls.length, 1); }); +test("case/getPortalModuleDetails composes BASE_URL route with encoded case reference", async () => { + const axios = createAxiosMock(); + const logger = createLoggerMock(); + + axios.getHandler = async () => ({ data: { value: [] } }); + + const caseService = loadServiceModule("caseDirectService.js", { + axios, + BASE_URL: "http://example.local", + consoleLogger: logger.consoleLogger + }); + + const result = await caseService.getPortalModuleDetails( + "appeal", + "REF A/B" + ); + + assert.deepStrictEqual(normalize(result), { value: [] }); + assert.strictEqual( + axios.calls[0].url, + "http://example.local/api/endpoint/getportalmoduledetails_api?appealType=appeal&caseReference=REF%20A/B" + ); +}); + test("admin/getNewAppealsPage returns res.data on success", async () => { const axios = createAxiosMock(); const logger = createLoggerMock();