fix(security): retire legacy direct CRM case creation endpoint

This commit is contained in:
2026-11-05 16:37:10 +00:00
parent 93bf7e174f
commit 9b0cb9adc8
6 changed files with 6 additions and 303 deletions
-29
View File
@@ -76,35 +76,6 @@ export const getAppealID = (
});
};
export const createNewCase = (
appealTypeId,
lpaID,
contactid,
createBody,
containerName
) => {
appealTypeId = parseInt(appealTypeId);
var data = createBody;
var queryUrl = buildFileQuery("/api/endpoint/createcase_api", {
appealTypeId,
lpaID,
contactid,
containername: containerName
});
var config = {
method: "post",
url: withBaseUrl(BASE_URL, queryUrl),
data: data
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const createNewCaseBlob = (
appealTypeId,
lpaID,
-2
View File
@@ -4,7 +4,6 @@ import {
getSIPSEvents,
getSIPSMedia,
getAppealID,
createNewCase,
createNewCaseBlob,
updateCase,
updateCaseBlob,
@@ -26,7 +25,6 @@ export {
getSIPSEvents,
getSIPSMedia,
getAppealID,
createNewCase,
createNewCaseBlob,
updateCase,
updateCaseBlob,
-7
View File
@@ -393,13 +393,6 @@ let CreateCase = (props) => {
delete values.confirmHASCAS;
// createNewCase(
// appTypeCollection.appealTypeID,
// values.lpaTypes,
// props.loggedInUser,
// values,
// props.containerID
// )
const selectedLpaName = props.LPAData.LPAData.value.filter((obj) => {
return obj.accountid === values.lpaTypes;
})[0].name;
-150
View File
@@ -1,150 +0,0 @@
/**
* @swagger
* /api/endpoint/createcase_api:
* post:
* tags: [Case]
* description: Create case
* summary: Phase 2
* parameters:
* - name: body
* in: requestbody
* required: true
* example: {}
* schema:
* type: object
* - name: contactid
* in: query
* required: true
* example: pinswg_planningappeals78s
* schema:
* type: string
* - name: appealTypeId
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* - name: containername
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* - name: lpaID
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* responses:
* 200:
* description: Success
*/
import axios from "axios";
import { consoleLogger } from "../../../actions/core/logger";
import { getToken } from "../../../actions/core/token";
import { getCaseBlob } from "../../../actions/azurestorage";
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/";
export default async function ApiProxy(req, res) {
const createCaseBody = req.body;
const contactid = req.query.contactid;
const appealTypeId = req.query.appealTypeId;
const containerName = req.query.containername;
const lpaID = req.query.lpaID;
const queryUrl = "incidents";
if (!createCaseBody || typeof createCaseBody !== "object") {
return respondError(res, {
status: 400,
code: "CASE_PAYLOAD_REQUIRED",
message: "Case payload is required"
});
}
if (typeof contactid !== "string" || contactid.trim().length === 0) {
return respondError(res, {
status: 400,
code: "CONTACT_ID_REQUIRED",
message: "contactid is required"
});
}
if (typeof appealTypeId !== "string" || appealTypeId.trim().length === 0) {
return respondError(res, {
status: 400,
code: "APPEAL_TYPE_ID_REQUIRED",
message: "appealTypeId is required"
});
}
if (
typeof containerName !== "string" ||
containerName.trim().length === 0
) {
return respondError(res, {
status: 400,
code: "CONTAINER_NAME_REQUIRED",
message: "containername is required"
});
}
if (typeof lpaID !== "string" || lpaID.trim().length === 0) {
return respondError(res, {
status: 400,
code: "LPA_ID_REQUIRED",
message: "lpaID is required"
});
}
try {
const token = await getToken();
const data = {
"title": "insertion test case",
"caseorigincode": 3,
"servicestage": 1,
"customerid_contact@odata.bind": "/contacts(" + contactid + ")",
"pinswg_appealcasetype": appealTypeId,
"pinswg_AssociatedLPA@odata.bind": "/accounts(" + lpaID + ")"
};
const newData = Object.assign(data, createCaseBody);
delete newData.lpaTypes;
delete newData.appealTypes;
console.log("/////Create Case:\n", newData, "\n//////////////");
const config = {
method: "post",
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Accept": "application/json",
"Prefer": 'odata.include-annotations="*",return=representation',
"Authorization": "Bearer " + token.access_token,
"Content-Type": "application/json"
},
data: JSON.stringify(newData)
};
const { data: responseData } = await axios(config);
await getCaseBlob(
containerName,
responseData.ticketnumber,
createCaseBody
);
return respondSuccess(res, responseData);
} catch (error) {
consoleLogger(error);
return respondError(res, {
status: 400,
code: "CASE_CREATE_FAILED",
message: "Failed to create case"
});
}
}
-43
View File
@@ -1,46 +1,3 @@
/**
* @swagger
* /api/endpoint/createcase_api:
* post:
* tags: [Case]
* description: Create case
* summary: Phase 2
* parameters:
* - name: body
* in: requestbody
* required: true
* example: {}
* schema:
* type: object
* - name: contactid
* in: query
* required: true
* example: pinswg_planningappeals78s
* schema:
* type: string
* - name: appealTypeId
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* - name: containername
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* - name: lpaID
* in: query
* required: true
* example: pinswg_planningappeals78id
* schema:
* type: string
* responses:
* 200:
* description: Success
*/
import axios from "axios";
import { isNonEmptyString, sanitizeString } from "../../../actions/core/guards";
import { consoleLogger } from "../../../actions/core/logger";
@@ -4624,76 +4624,6 @@ test("getappealpdfdocuments catch path returns APPEAL_PDF_DOCUMENTS_FETCH_FAILED
);
});
test("createcase returns CASE_PAYLOAD_REQUIRED when body missing", async () => {
const mod = loadModule("pages/api/endpoint/createcase_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
getCaseBlob: async () => {},
hashAPIPath: () => "&hash=expected",
axios: async () => ({ data: { ticketnumber: "CAS-1" } }),
consoleLogger: () => {}
});
const req = { query: {}, body: undefined };
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(res.state.jsonBody.error.code, "CASE_PAYLOAD_REQUIRED");
});
test("createcase returns CONTACT_ID_REQUIRED when contactid missing", async () => {
const mod = loadModule("pages/api/endpoint/createcase_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
getCaseBlob: async () => {},
hashAPIPath: () => "&hash=expected",
axios: async () => ({ data: { ticketnumber: "CAS-1" } }),
consoleLogger: () => {}
});
const req = {
query: { appealTypeId: "a1", containername: "c1", lpaID: "l1" },
body: { title: "x" }
};
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED");
});
test("createcase catch path returns CASE_CREATE_FAILED", async () => {
const mod = loadModule("pages/api/endpoint/createcase_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
getCaseBlob: async () => {},
hashAPIPath: () => "&hash=expected",
axios: async () => {
throw new Error("create failed");
},
consoleLogger: () => {}
});
const req = {
query: {
contactid: "c1",
appealTypeId: "a1",
containername: "container",
lpaID: "l1"
},
body: { title: "x" }
};
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(res.state.jsonBody.error.code, "CASE_CREATE_FAILED");
});
test("updatecase returns CASE_UPDATE_PAYLOAD_REQUIRED when body missing", async () => {
const mod = loadModule("pages/api/endpoint/updatecase_api.js", {
respondError: respondErrorMock,
@@ -4836,7 +4766,8 @@ test("gethash returns UNAUTHENTICATED when session missing", async () => {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
hashAPIPath: () => "&hash=expected",
getSession: async () => null,
getServerSession: async () => null,
authOptions: () => ({}),
nextConnect: () => {
const handler = { registeredGet: null };
handler.get = (cb) => {
@@ -4860,7 +4791,10 @@ test("gethash returns INVALID_HASH_PATH when path is invalid", async () => {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
hashAPIPath: () => "&hash=expected",
getSession: async () => ({ user: { email: "user@test.local" } }),
getServerSession: async () => ({
user: { email: "user@test.local" }
}),
authOptions: () => ({}),
nextConnect: () => {
const handler = { registeredGet: null };
handler.get = (cb) => {