From ae64ee6c2b567d0e773491b01d52f05f9caed409 Mon Sep 17 00:00:00 2001 From: robbond Date: Wed, 25 Mar 2026 11:36:59 +0000 Subject: [PATCH] refactor(portal): normalize route composition with fileRouteBuilder --- actions/services/portalDirectService.js | 183 ++++++++++++++---------- memory-bank/change-log.md | 42 ++++++ 2 files changed, 149 insertions(+), 76 deletions(-) diff --git a/actions/services/portalDirectService.js b/actions/services/portalDirectService.js index a041bf5a..9adc69bc 100644 --- a/actions/services/portalDirectService.js +++ b/actions/services/portalDirectService.js @@ -2,104 +2,124 @@ import { BASE_URL } from "../core/env"; import { consoleLogger } from "../core/logger"; import { buildHashedQueryUrl } from "../clients/relayClient"; import { getJson, requestJson } from "../clients/endpointClient"; +import { + buildFileQuery, + withBaseUrl, + appendQuerySuffix +} from "../clients/fileRouteBuilder"; export const getMyCases = (loggedInUserId) => { - return getJson( - BASE_URL + - "/api/endpoint/getmycases_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getmycases_api", { + loggedInUserId + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getMyInvolvements = async (loggedInUserId) => { - return getJson( - BASE_URL + - "/api/endpoint/getmyinvolvements_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getmyinvolvements_api", { + loggedInUserId + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getMyLPACases = (lpaid) => { - return getJson( - BASE_URL + "/api/endpoint/getmylpacases_api?lpaid=" + lpaid - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getmylpacases_api", { + lpaid + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getMyRepresentations = (loggedInUserId) => { - return getJson( - BASE_URL + - "/api/endpoint/getmyrepresentations_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getmyrepresentations_api", { + loggedInUserId + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getMyRepresentationsProxy = (loggedInUserId) => { - return getJson( - "/api/endpoint/getmyrepresentationsproxy_api?loggedInUserId=" + + const route = buildFileQuery( + "/api/endpoint/getmyrepresentationsproxy_api", + { loggedInUserId - ).catch((error) => { + } + ); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; export const getRepresentations = (incidentID) => { - return getJson( - "/api/endpoint/getrepresentations_api?incidentID=" + incidentID - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getrepresentations_api", { + incidentID + }); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; export const getRepresentationsProxy = (incidentID) => { - return getJson( - "/api/endpoint/getrepresentationsproxy_api?incidentID=" + incidentID - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getrepresentationsproxy_api", { + incidentID + }); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; export const getWatchedCases = (loggedInUserId) => { - return getJson( - BASE_URL + - "/api/endpoint/getwatchedcases_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getwatchedcases_api", { + loggedInUserId + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; export const getWatchedCasesProxy = (loggedInUserId) => { - return getJson( - "/api/endpoint/getwatchedcasesproxy_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getwatchedcasesproxy_api", { + loggedInUserId + }); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; export const getAwaitingSubmissionProxy = (loggedInUserId) => { - return getJson( - "/api/endpoint/getawaitingsubmissionproxy_api?loggedInUserId=" + + const route = buildFileQuery( + "/api/endpoint/getawaitingsubmissionproxy_api", + { loggedInUserId - ).catch((error) => { + } + ); + + return getJson(route).catch((error) => { consoleLogger(error); }); }; export const getAwaitingSubmission = (loggedInUserId) => { - return getJson( - BASE_URL + - "/api/endpoint/getawaitingsubmission_api?loggedInUserId=" + - loggedInUserId - ).catch((error) => { + const route = buildFileQuery("/api/endpoint/getawaitingsubmission_api", { + loggedInUserId + }); + + return getJson(withBaseUrl(BASE_URL, route)).catch((error) => { consoleLogger(error); }); }; @@ -122,9 +142,9 @@ export const createWatchedCases = async (formValues) => { }; export const deleteMyRepresentations = (myRepresentationsID) => { - var queryUrl = - "/api/endpoint/deletemyrepresentations_api?myRepresentationsID=" + - myRepresentationsID; + var queryUrl = buildFileQuery("/api/endpoint/deletemyrepresentations_api", { + myRepresentationsID + }); return buildHashedQueryUrl(queryUrl) .then((signedUrl) => @@ -147,8 +167,12 @@ export const deleteMyRepresentations = (myRepresentationsID) => { }; export const deleteAwaitingSubmissions = (incidentID) => { - var queryUrl = - "/api/endpoint/deleteawaitingsubmissions_api?incidentID=" + incidentID; + var queryUrl = buildFileQuery( + "/api/endpoint/deleteawaitingsubmissions_api", + { + incidentID + } + ); var config = { method: "delete", @@ -161,8 +185,9 @@ export const deleteAwaitingSubmissions = (incidentID) => { }; export const deleteWatchedCases = async (watchedCaseID) => { - var queryUrl = - "/api/endpoint/deletewatchedcases_api?watchedCaseID=" + watchedCaseID; + var queryUrl = buildFileQuery("/api/endpoint/deletewatchedcases_api", { + watchedCaseID + }); return buildHashedQueryUrl(queryUrl) .then((signedUrl) => @@ -181,23 +206,26 @@ export const sendCaseCompleteMessage = async ( caseReference, inv ) => { - var hashQueryPath = - "/api/file/createappealcompletemessage_api?container=" + - containerID + - "&tempcaseref=" + - caseReference; + var hashQueryPath = buildFileQuery( + "/api/file/createappealcompletemessage_api", + { + container: containerID, + tempcaseref: caseReference + } + ); - var queryUrl = - "/api/file/createappealcompletemessage_api?container=" + - containerID + - "&tempcaseref=" + - caseReference + - "&inv=" + - inv; + var queryUrl = buildFileQuery("/api/file/createappealcompletemessage_api", { + container: containerID, + tempcaseref: caseReference, + inv + }); var signedQueryUrl = await buildHashedQueryUrl(hashQueryPath); - queryUrl = queryUrl + signedQueryUrl.replace(hashQueryPath, ""); + queryUrl = appendQuerySuffix( + queryUrl, + signedQueryUrl.replace(hashQueryPath, "") + ); var config = { method: "get", @@ -213,11 +241,13 @@ export const sendCaseCompleteMessageProxy = async ( containerID, caseReference ) => { - var queryUrl = - "/api/file/createappealcompletemessageproxy_api?container=" + - containerID + - "&tempcaseref=" + - caseReference; + var queryUrl = buildFileQuery( + "/api/file/createappealcompletemessageproxy_api", + { + container: containerID, + tempcaseref: caseReference + } + ); var config = { method: "get", @@ -234,13 +264,14 @@ export const sendRepCompleteMessage = async ( caseReference, fileName ) => { - var hashQueryPath = - "/api/file/createrepcompletemessage_api?container=" + - containerID + - "&tempcaseref=" + - caseReference + - "&repid=" + - fileName; + var hashQueryPath = buildFileQuery( + "/api/file/createrepcompletemessage_api", + { + container: containerID, + tempcaseref: caseReference, + repid: fileName + } + ); var queryUrl = await buildHashedQueryUrl(hashQueryPath); diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index b4ec2ab6..b6e43175 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -2517,3 +2517,45 @@ Validation: Follow-ups: - Optional next widened slice: evaluate applying `fileRouteBuilder` to portal/case service file-route call sites for cross-module query-builder consistency. + +--- + +### CL-071: TASK22260 next widened cross-module slice — portal service query normalization via fileRouteBuilder + +date: 2026-03-25 +author: Cline +scope: `actions/services/portalDirectService.js` +type: change +rationale: Deliver the requested next wider slice by extending `fileRouteBuilder` adoption beyond document service into portal service, reducing duplicated query string concatenation and improving consistency in signed/unsigned route construction. +impact: Improves maintainability and query-construction consistency across high-use portal service flows while preserving existing runtime behavior and hash-signing contracts. +status: completed + +Summary: + +- Refactored `actions/services/portalDirectService.js` to use shared route helpers: + - `buildFileQuery` + - `withBaseUrl` + - `appendQuerySuffix` +- Normalized query composition across portal service GET/DELETE/message flows: + - read/list endpoints (`getMyCases`, `getMyInvolvements`, `getMyLPACases`, `getMyRepresentations`, proxy and watched/awaiting variants) + - delete endpoints (`deleteMyRepresentations`, `deleteAwaitingSubmissions`, `deleteWatchedCases`) + - file-message endpoints (`sendCaseCompleteMessage`, `sendCaseCompleteMessageProxy`, `sendRepCompleteMessage`) +- Preserved behavior contracts: + - retained BASE_URL usage patterns for existing BASE_URL-prefixed routes + - retained hash-signing flow via `buildHashedQueryUrl` + - retained append semantics for signed suffixes in `sendCaseCompleteMessage` + - retained request methods, headers, payloads, and catch-path logging + +Validation: + +- `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: apply the same query-normalization helpers in `caseDirectService` and add dedicated phase22 behavioral assertions for `portalDirectService` route-building/signing composition.