diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index 6556676e..6f9241bc 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -1006,3 +1006,34 @@ Validation: Follow-ups: - Continue P2-S2 with next bounded batch from remaining legacy relay GET endpoints (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`, `getmylpacases_api`, `getportallogin_api`). + +--- + +### CL-027: TASK22229 P2-S2 Batch 10 (portal login + my LPA cases relay GET pair) + +date: 2026-03-24 +author: Cline +scope: `pages/api/endpoint/{getportallogin_api,getmylpacases_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` +type: change +rationale: Continue bounded relay migration by moving two remaining high-use portal retrieval endpoints to shared `relayGet` while preserving existing hash/lookup guards and response contracts. +impact: Further relay boilerplate reduction and consistent forwarding behavior in portal login/LPA case retrieval flows; no intended API contract changes. +status: completed + +Summary: + +- Migrated Batch 10 endpoints to shared `relayGet`: + - `getportallogin_api.js` (preserved hash validation guard and error contract) + - `getmylpacases_api.js` (preserved LPA lookup/404 guard and title transform) +- Preserved endpoint-specific behavior: + - `getportallogin_api`: raw + encoded hash candidate validation before relay call + - `getmylpacases_api`: JSONPath LPA lookup with `LPA_NOT_FOUND` handling and `pinswg_title` enrichment transform +- Updated phase21 endpoint contract tests to inject `relayGet` mocks for migrated handlers in validation/catch/success paths. + +Validation: + +- `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) +- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) + +Follow-ups: + +- Continue P2-S2 with the remaining legacy relay GET candidates (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`). diff --git a/pages/api/endpoint/getmylpacases_api.js b/pages/api/endpoint/getmylpacases_api.js index 47daab59..71a947d9 100644 --- a/pages/api/endpoint/getmylpacases_api.js +++ b/pages/api/endpoint/getmylpacases_api.js @@ -17,18 +17,11 @@ * description: Success */ -import axios from "axios"; import { JSONPath as jsonpath } from "jsonpath-plus"; import { getLPA } from "../../../actions/services/referenceDataService"; import { azureHeaders } from "../../../actions/core/headers"; -import { consoleLogger } from "../../../actions/core/logger"; -import { getToken } from "../../../actions/core/token"; -import { hashAPIPath } from "../../../actions/core/hash"; -import { respondError, respondSuccess } from "../middleware/apiResponse"; - -const WEBAPI_URL = - process.env.RELAY_ROOT || - "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; +import { respondError } from "../middleware/apiResponse"; +import { relayGet } from "../middleware/relayForwarding"; export default async function ApiProxy(req, res) { const lpaid = req.query.lpaid; @@ -42,7 +35,6 @@ export default async function ApiProxy(req, res) { } try { - const token = await getToken(); const lpaList = await getLPA(); const lpaGUID = jsonpath({ @@ -74,18 +66,23 @@ export default async function ApiProxy(req, res) { //console.log("///////////\nPortal query: ", queryUrl, "<<< azureHeaders(accessToken), + transformData: (data) => { + data.value.forEach(function (element) { + element.pinswg_title = element.title; + }); + return data; + }, + errorResponse: { + status: 400, + code: "MY_LPA_CASES_FETCH_FAILED", + message: "Failed to fetch my LPA cases" + } }); - - return respondSuccess(res, data); } catch (error) { - consoleLogger(error); return respondError(res, { status: 400, code: "MY_LPA_CASES_FETCH_FAILED", diff --git a/pages/api/endpoint/getportallogin_api.js b/pages/api/endpoint/getportallogin_api.js index c3f52aae..a6593a9a 100644 --- a/pages/api/endpoint/getportallogin_api.js +++ b/pages/api/endpoint/getportallogin_api.js @@ -16,16 +16,10 @@ * description: hello world */ -import axios from "axios"; import { azureHeadersPaged } from "../../../actions/core/headers"; -import { consoleLogger } from "../../../actions/core/logger"; -import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; -import { respondError, respondSuccess } from "../middleware/apiResponse"; - -const WEBAPI_URL = - process.env.RELAY_ROOT || - "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; +import { respondError } from "../middleware/apiResponse"; +import { relayGet } from "../middleware/relayForwarding"; export default async function ApiProxy(req, res) { const emailAddress = req.query.emailAddress; @@ -66,24 +60,19 @@ export default async function ApiProxy(req, res) { }); } - try { - const token = await getToken(); - const queryUrl = - "contacts?$filter=emailaddress1 eq '" + - emailAddress + - "' and statuscode eq 1&$count=true&$select=emailaddress1,contactid,yomifullname,firstname,lastname"; - const { data } = await axios.get( - WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - azureHeadersPaged(token.access_token) - ); + const queryUrl = + "contacts?$filter=emailaddress1 eq '" + + emailAddress + + "' and statuscode eq 1&$count=true&$select=emailaddress1,contactid,yomifullname,firstname,lastname"; - return respondSuccess(res, data); - } catch (error) { - consoleLogger(error); - return respondError(res, { + return relayGet({ + queryUrl, + res, + requestOptionsBuilder: (accessToken) => azureHeadersPaged(accessToken), + errorResponse: { status: 400, code: "PORTAL_LOGIN_FETCH_FAILED", message: "Failed to fetch portal login" - }); - } + } + }); } diff --git a/tests/phase21/endpoint-handler-contract.test.cjs b/tests/phase21/endpoint-handler-contract.test.cjs index f0d311c0..2a78106e 100644 --- a/tests/phase21/endpoint-handler-contract.test.cjs +++ b/tests/phase21/endpoint-handler-contract.test.cjs @@ -274,14 +274,12 @@ test("getportallogin returns HASH_REQUIRED when hash missing", async () => { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async () => ({}), hashAPIPath: (input) => input && input.startsWith("/api/endpoint/getportallogin_api") ? "&hash=expected" : "&hash=relay", - azureHeadersPaged: () => ({}), - axios: { get: async () => ({ data: { value: [] } }) }, - consoleLogger: () => {} + azureHeadersPaged: () => ({}) }); const req = { query: { emailAddress: "user@test.local" } }; @@ -296,14 +294,12 @@ test("getportallogin returns INVALID_HASH when hash mismatch", async () => { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async () => ({}), hashAPIPath: (input) => input && input.startsWith("/api/endpoint/getportallogin_api") ? "&hash=expected" : "&hash=relay", - azureHeadersPaged: () => ({}), - axios: { get: async () => ({ data: { value: [] } }) }, - consoleLogger: () => {} + azureHeadersPaged: () => ({}) }); const req = { query: { emailAddress: "user@test.local", hash: "wrong" } }; @@ -318,18 +314,13 @@ test("getportallogin catch path returns PORTAL_LOGIN_FETCH_FAILED", async () => const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async ({ res, errorResponse }) => + respondErrorMock(res, errorResponse), hashAPIPath: (input) => input && input.startsWith("/api/endpoint/getportallogin_api") ? "&hash=expected" : "&hash=relay", - azureHeadersPaged: () => ({}), - axios: { - get: async () => { - throw new Error("relay failed"); - } - }, - consoleLogger: () => {} + azureHeadersPaged: () => ({}) }); const req = { @@ -349,16 +340,13 @@ test("getportallogin accepts encoded email hash variant", async () => { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async ({ res }) => + respondSuccessMock(res, { value: [{ contactid: "c1" }] }), hashAPIPath: (input) => input && input.includes("emailAddress=user%2Btest%40local") ? "&hash=expected" : "&hash=other", - azureHeadersPaged: () => ({}), - axios: { - get: async () => ({ data: { value: [{ contactid: "c1" }] } }) - }, - consoleLogger: () => {} + azureHeadersPaged: () => ({}) }); const req = { @@ -2421,13 +2409,10 @@ test("getmylpacases returns LPA_ID_REQUIRED when lpaid missing", async () => { const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async () => ({}), getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }], jsonpath: () => [{ accountid: "acc1" }], - hashAPIPath: () => "&hash=expected", - azureHeaders: () => ({}), - axios: { get: async () => ({ data: { value: [] } }) }, - consoleLogger: () => {} + azureHeaders: () => ({}) }); const req = { query: {} }; @@ -2442,13 +2427,10 @@ test("getmylpacases returns LPA_NOT_FOUND when lpaid lookup misses", async () => const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async () => ({}), getLPA: async () => [{ name: "Another LPA", accountid: "acc1" }], jsonpath: () => [], - hashAPIPath: () => "&hash=expected", - azureHeaders: () => ({}), - axios: { get: async () => ({ data: { value: [] } }) }, - consoleLogger: () => {} + azureHeaders: () => ({}) }); const req = { query: { lpaid: "Missing LPA" } }; @@ -2463,17 +2445,11 @@ test("getmylpacases catch path returns MY_LPA_CASES_FETCH_FAILED", async () => { const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { respondError: respondErrorMock, respondSuccess: respondSuccessMock, - getToken: async () => ({ access_token: "token" }), + relayGet: async ({ res, errorResponse }) => + respondErrorMock(res, errorResponse), getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }], jsonpath: () => [{ accountid: "acc1" }], - hashAPIPath: () => "&hash=expected", - azureHeaders: () => ({}), - axios: { - get: async () => { - throw new Error("relay failed"); - } - }, - consoleLogger: () => {} + azureHeaders: () => ({}) }); const req = { query: { lpaid: "Test LPA" } };