Merged PR 2182: update apis with standardised response helpers

Related work items: #22102
This commit is contained in:
Robert Bond
2026-03-17 13:38:06 +00:00
36 changed files with 737 additions and 201 deletions
+1
View File
@@ -2,6 +2,7 @@
## Current development focus (from recent commits)
- API contract consistency rollout (TASK22102), starting with helper-based response normalization in selected email/admin handlers.
- Search/case navigation correctness, especially breadcrumb and back-link behavior.
- My Portal "view all" and DNS application path handling.
- Welsh/English email behavior for specific notification templates.
+206
View File
@@ -1302,3 +1302,209 @@ Validation:
Follow-ups:
- Continue same small-batch consistency pattern for remaining endpoint handlers where required-input/logging drift is clear.
---
### CL-035: TASK22102 API contract consistency — Slice 1 (response helper + email/admin pilot)
date: 2026-03-17
author: Cline
scope: `pages/api/middleware/apiResponse.js`, `pages/api/email/{notify,getmailinglist}.js`, `pages/api/admin/{getnewappeals_api,getlatestdocuments_api}.js`, `memory-bank/*`
type: change
rationale: Start API contract-consistency program with a low-risk pilot slice introducing shared response helpers and replacing raw error passthrough in selected email/admin handlers.
impact: Improves response contract consistency and prevents raw error payload leakage in pilot handlers while preserving existing success-body compatibility.
status: completed
Summary:
- Added shared API response helper module:
- `pages/api/middleware/apiResponse.js`
- `respondSuccess(res, data, status)`
- `respondError(res, { status, code, message, details })`
- Migrated first slice handlers to helper-based responses:
- `pages/api/email/notify.js`
- `pages/api/email/getmailinglist.js`
- `pages/api/admin/getnewappeals_api.js`
- `pages/api/admin/getlatestdocuments_api.js`
- Contract updates in slice:
- replaced `res.status(400).json(error)` with structured error envelope
- replaced direct `res.status(200).json(...)` with `respondSuccess(...)`
- kept success payload shape as existing data object for non-breaking rollout
Validation:
- `npx next lint --file pages/api/middleware/apiResponse.js --file pages/api/email/notify.js --file pages/api/email/getmailinglist.js --file pages/api/admin/getnewappeals_api.js --file pages/api/admin/getlatestdocuments_api.js` -> pass (no warnings/errors)
Follow-ups:
- Slice 2 should migrate remaining email handlers (`getcaseref`, `getall`, `getevents`, `getdocuments`) to helper responses.
- After email/admin completion, expand to selected high-risk file handlers using same non-breaking helper model.
---
### CL-036: TASK22102 API contract consistency — Slice 2 (remaining email handlers)
date: 2026-03-17
author: Cline
scope: `pages/api/email/{getcaseref,getall,getevents,getdocuments}.js`
type: change
rationale: Complete the email-domain response-contract consistency rollout by moving remaining handlers to shared helper-based success/error responses.
impact: Removes raw error passthrough in remaining email handlers and standardizes structured error envelopes while preserving success payload compatibility.
status: completed
Summary:
- Migrated remaining email handlers to shared response helper usage:
- `getcaseref`
- `getall`
- `getevents`
- `getdocuments`
- Replaced direct `res.status(...).json(...)` branches with:
- `respondSuccess(...)`
- `respondError(...)`
- Added stable error codes/messages for expected negative paths and catch branches.
Validation:
- `npx next lint --file pages/api/email/getcaseref.js --file pages/api/email/getevents.js --file pages/api/email/getdocuments.js --file pages/api/email/getall.js` -> pass (no warnings/errors)
Follow-ups:
- Next slice can target selected file handlers for equivalent response contract cleanup.
---
### CL-037: TASK22102 API contract consistency — Slice 3 (file proxy handlers)
date: 2026-03-17
author: Cline
scope: `pages/api/file/{getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy,createappealcompletemessageproxy_api}.js`
type: change
rationale: Extend contract consistency into selected proxy file handlers by replacing raw error passthrough and empty 400s with standardized structured responses.
impact: Improves API error contract clarity for selected file proxy routes while preserving success payload pass-through behavior.
status: completed
Summary:
- Migrated selected file proxy handlers to shared response helper usage:
- `getbloblistproxy`
- `getrepsblobproxy`
- `getawaitingsubmissionfromblobproxy`
- `createappealcompletemessageproxy_api`
- Replaced direct `res.status(...).json(...)` handling with:
- `respondSuccess(...)`
- `respondError(...)`
- Added explicit structured 400 responses for missing required query values and proxy fetch failures.
Validation:
- `npx next lint --file pages/api/file/getbloblistproxy.js --file pages/api/file/getrepsblobproxy.js --file pages/api/file/getawaitingsubmissionfromblobproxy.js --file pages/api/file/createappealcompletemessageproxy_api.js` -> pass (no warnings/errors)
Follow-ups:
- Next slice should target non-proxy file handlers that still return raw `error` payloads.
---
### CL-038: TASK22102 API contract consistency — Slice 4 (security hardening + larger non-proxy file set)
date: 2026-03-17
author: Cline
scope: `pages/api/middleware/apiResponse.js`, `pages/api/file/{createappealcompletemessage_api,updatecase_api,createcaseinvolvement_api,createrepinvolvement_api,createcase_api,generatepdf}.js`
type: change
rationale: Apply requested security hardening for error detail exposure and deliver a larger non-proxy file-handler slice to improve codex usage efficiency while keeping contract risk low.
impact: Suppresses sensitive `details` payloads in production, improves structured API consistency in selected non-proxy file handlers, and preserves existing success-path payload compatibility.
status: completed
Summary:
- Hardened shared error helper:
- `respondError` now omits `error.details` when `NODE_ENV === "production"`.
- debug detail visibility remains available in non-production environments.
- Migrated a larger batch of non-proxy file handlers to helper-based responses:
- `createappealcompletemessage_api`
- `updatecase_api`
- `createcaseinvolvement_api`
- `createrepinvolvement_api`
- `createcase_api`
- `generatepdf`
- Standardized missing-input/hash/failure paths to structured `respondError` codes/messages while retaining success bodies and existing 200 semantics (including 412->record exists handling in involvement endpoints).
Validation:
- `npx next lint --file pages/api/middleware/apiResponse.js --file pages/api/file/createappealcompletemessage_api.js --file pages/api/file/updatecase_api.js --file pages/api/file/createcaseinvolvement_api.js --file pages/api/file/createrepinvolvement_api.js --file pages/api/file/createcase_api.js --file pages/api/file/generatepdf.js` -> pass (no warnings/errors)
Follow-ups:
- Continue next larger slice on remaining non-proxy file handlers still returning raw error payloads.
---
### CL-039: TASK22102 API contract consistency — Slice 5 (larger file-handler batch)
date: 2026-03-17
author: Cline
scope: `pages/api/file/{uploadsinglefile,setupcontainer,createrepcompletemessage_api,editRepJson}.js`
type: change
rationale: Continue with a larger efficiency-focused slice by migrating remaining high-signal file handlers that still returned raw/empty error responses.
impact: Improves response-contract consistency and avoids leaking raw error payloads in selected file handlers while preserving success behavior and endpoint semantics.
status: completed
Summary:
- Migrated additional file handlers to helper-based responses:
- `uploadsinglefile`
- `setupcontainer`
- `createrepcompletemessage_api`
- `editRepJson`
- Replaced direct `res.status(...).json(...)` error branches (including raw `error` payload and empty responses) with structured:
- `respondError(...)`
- `respondSuccess(...)`
- Preserved existing success semantics:
- `uploadsinglefile` still returns uploaded result + `invalidFiles`
- `setupcontainer` still returns `{ data: "success", output }`
- `editRepJson` still returns success message on completion
Validation:
- `npx next lint --file pages/api/file/uploadsinglefile.js --file pages/api/file/setupcontainer.js --file pages/api/file/createrepcompletemessage_api.js --file pages/api/file/editRepJson.js` -> pass (no warnings/errors)
Follow-ups:
- Continue next larger slice on remaining file handlers with empty 400 responses to complete contract-consistency rollout.
---
### CL-040: TASK22102 API contract consistency — Slice 6 (CRUD/blob retrieval group)
date: 2026-03-17
author: Cline
scope: `pages/api/file/{deleteblob,deleteblobcase,deleteblobrep,deleteawaitingsubmissionfromblob,getprogressobjblob,getawaitingsubmissionfromblob,getrepsblob}.js`
type: change
rationale: Deliver the first of two remaining larger slices by standardizing response contracts across blob CRUD and retrieval handlers still using direct/empty response patterns.
impact: Improves consistency and safety of error responses in selected blob handlers while preserving existing success payload behavior and cache-control semantics.
status: completed
Summary:
- Migrated 7 blob CRUD/retrieval handlers to `respondSuccess`/`respondError`:
- `deleteblob`
- `deleteblobcase`
- `deleteblobrep`
- `deleteawaitingsubmissionfromblob`
- `getprogressobjblob`
- `getawaitingsubmissionfromblob`
- `getrepsblob`
- Replaced empty `400` and direct status responses with structured error envelopes including explicit codes/messages.
- Removed redundant post-hash equality branches where equivalent logic was already guaranteed after early guard checks.
- Preserved response behavior:
- existing success data payload shapes retained (`{ data: ... }` or direct data payloads)
- `getrepsblob` retains `Cache-Control: no-store` header.
Validation:
- `npx next lint --file pages/api/file/deleteblob.js --file pages/api/file/deleteblobcase.js --file pages/api/file/deleteblobrep.js --file pages/api/file/deleteawaitingsubmissionfromblob.js --file pages/api/file/getprogressobjblob.js --file pages/api/file/getawaitingsubmissionfromblob.js --file pages/api/file/getrepsblob.js` -> pass (no warnings/errors)
Follow-ups:
- Execute final Slice 7 for remaining complex handlers (`upload`, `getbloblist`, `downloadblob`, `generateappealpdf`) to complete the 2-slice finish plan.
+7 -2
View File
@@ -22,6 +22,7 @@ import { azureHeadersPagedCustom } 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 WORDKEY = process.env.HASHKEY;
const WEBAPI_URL =
@@ -154,11 +155,15 @@ export default async function ApiProxy(req, res) {
_.has(data, "@odata.nextLink") == true &&
((dataStr = JSON.stringify(data["@odata.nextLink"])),
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "ADMIN_LATEST_DOCS_FETCH_FAILED",
message: "Failed to fetch latest documents"
});
});
return apiResponse;
+7 -2
View File
@@ -22,6 +22,7 @@ import { azureHeadersPagedCustom } from "../../../actions/core/headers";
import { getToken } from "../../../actions/core/token";
import { consoleLogger } from "../../../actions/core/logger";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const WEBAPI_URL =
process.env.RELAY_ROOT ||
@@ -64,11 +65,15 @@ export default async function ApiProxy(req, res) {
_.has(data, "@odata.nextLink") == true &&
((dataStr = JSON.stringify(data["@odata.nextLink"])),
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "ADMIN_NEW_APPEALS_FETCH_FAILED",
message: "Failed to fetch new appeals"
});
});
return apiResponse;
+6 -3
View File
@@ -6,6 +6,7 @@ import { consoleLogger } from "../../../actions/core/logger";
import { getToken } from "../../../actions/core/token";
import { formatDates } from "../../../components/utils";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
var NotifyClient = require("notifications-node-client").NotifyClient;
@@ -439,11 +440,13 @@ export default async function CombinedApiProxy(req, res) {
sendingResults.push(result);
}
res.status(200).json({ sendingResults });
return respondSuccess(res, { sendingResults });
} catch (error) {
consoleLogger(error);
res.status(500).json({
error: "An error occurred while retrieving combined data.",
return respondError(res, {
status: 500,
code: "EMAIL_COMBINED_FETCH_FAILED",
message: "An error occurred while retrieving combined data.",
details: error.message || error.toString()
});
}
+7 -3
View File
@@ -5,6 +5,7 @@ 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 ||
@@ -23,7 +24,6 @@ function flattenWatchlistEntry(entry) {
}
export default async function ApiProxy(req, res) {
const incidentID = req.query.incidentid;
var token = await getToken();
var queryUrl =
@@ -39,10 +39,14 @@ export default async function ApiProxy(req, res) {
const flattenedResults = data.value.map(flattenWatchlistEntry);
res.status(200).json(flattenedResults);
return respondSuccess(res, flattenedResults);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "CASE_REF_FETCH_FAILED",
message: "Failed to fetch case references"
});
});
}
+11 -6
View File
@@ -5,6 +5,7 @@ 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 WORDKEY = process.env.HASHKEY;
const WEBAPI_URL =
@@ -26,9 +27,11 @@ export default async function ApiProxy(req, res) {
const incidentID = req.query.incidentid;
if (!incidentID) {
return res
.status(400)
.json({ error: "incidentid query parameter is required." });
return respondError(res, {
status: 400,
code: "INCIDENT_ID_REQUIRED",
message: "incidentid query parameter is required."
});
}
try {
@@ -79,11 +82,13 @@ export default async function ApiProxy(req, res) {
)
}));
res.status(200).json({ ...data, value: resultsWithLinks });
return respondSuccess(res, { ...data, value: resultsWithLinks });
} catch (error) {
consoleLogger(error);
res.status(500).json({
error: "Failed to fetch document details.",
return respondError(res, {
status: 500,
code: "DOCUMENTS_FETCH_FAILED",
message: "Failed to fetch document details.",
details: error.message || error.toString()
});
}
+16 -7
View File
@@ -5,6 +5,7 @@ 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 WORDKEY = process.env.HASHKEY;
const WEBAPI_URL =
@@ -18,7 +19,11 @@ export default async function ApiProxy(req, res) {
const { incidentID } = req.query;
if (!incidentID) {
return res.status(400).json({ error: "incidentID is required" });
return respondError(res, {
status: 400,
code: "INCIDENT_ID_REQUIRED",
message: "incidentID is required"
});
}
try {
@@ -34,9 +39,11 @@ export default async function ApiProxy(req, res) {
const sipsRecords = _.get(sipsResponse, "data.value", []);
if (sipsRecords.length === 0) {
return res
.status(404)
.json({ error: "No SIPs record found for this incidentID." });
return respondError(res, {
status: 404,
code: "SIPS_RECORD_NOT_FOUND",
message: "No SIPs record found for this incidentID."
});
}
const sipsId = sipsRecords[0].pinswg_sipsid;
@@ -53,11 +60,13 @@ export default async function ApiProxy(req, res) {
azureHeaders(token.access_token)
);
res.status(200).json(eventsResponse.data);
return respondSuccess(res, eventsResponse.data);
} catch (error) {
consoleLogger(error);
res.status(500).json({
error: "An error occurred while retrieving data.",
return respondError(res, {
status: 500,
code: "EVENTS_FETCH_FAILED",
message: "An error occurred while retrieving data.",
details: error.message || error.toString()
});
}
+7 -2
View File
@@ -5,6 +5,7 @@ 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 WORDKEY = process.env.HASHKEY;
@@ -40,10 +41,14 @@ export default async function ApiProxy(req, res) {
const flattenedResults = data.value.map(flattenWatchlistEntry);
res.status(200).json(flattenedResults);
return respondSuccess(res, flattenedResults);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "MAILING_LIST_FETCH_FAILED",
message: "Failed to fetch mailing list"
});
});
}
+12 -3
View File
@@ -28,13 +28,18 @@
import { consoleLogger, redactSensitive } from "../../../actions/core/logger";
import { isNonEmptyString, sanitizeString } from "../../../actions/core/guards";
import { getPreferredLanguage } from "../../../actions/services/accountService";
import { respondError, respondSuccess } from "../middleware/apiResponse";
export default async function ApiProxy(req, res) {
var data = req.body;
const emailAddress = sanitizeString(data?.emailAddress);
if (!isNonEmptyString(emailAddress)) {
return res.status(400).json({ error: "emailAddress is required" });
return respondError(res, {
status: 400,
code: "EMAIL_ADDRESS_REQUIRED",
message: "emailAddress is required"
});
}
data.emailAddress = emailAddress;
@@ -71,11 +76,15 @@ export default async function ApiProxy(req, res) {
})
.then((response) => {
//console.log("thisis the response", response);
return res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
return res.status(400).json(error);
return respondError(res, {
status: 400,
code: "EMAIL_NOTIFY_FAILED",
message: "Failed to send notify email"
});
});
//return res.status(200).json(data);
}
@@ -12,6 +12,7 @@ import _ from "lodash";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
@@ -30,7 +31,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, tempcaseref and hash are required"
});
}
var checkquerypath =
@@ -40,7 +45,11 @@ ApiProxy.get(async (req, res) => {
tempCaseRef;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
const blobProgress = await getProgressBlobs(
@@ -107,14 +116,18 @@ ApiProxy.get(async (req, res) => {
}
createCaseCompleteMessage(containerName, tempCaseRef);
return res.status(200).json({
return respondSuccess(res, {
status: "success"
});
});
})
.catch((error) => {
consoleLogger(error);
return res.status(400).json(error);
return respondError(res, {
status: 400,
code: "CREATE_APPEAL_COMPLETE_MESSAGE_FAILED",
message: "Failed to create appeal complete message"
});
});
});
@@ -3,6 +3,7 @@ import { getToken } from "../../../actions/core/token";
import { azureHeaders } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger";
import axios from "axios";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -20,7 +21,11 @@ ApiProxy.get(async (req, res) => {
var tempCaseRef = req.query.tempcaseref;
if (!hasValue(containerName) || !hasValue(tempCaseRef)) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container and tempcaseref are required"
});
}
var token = await getToken();
@@ -37,11 +42,15 @@ ApiProxy.get(async (req, res) => {
azureHeaders(token.access_token)
)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "CREATE_APPEAL_COMPLETE_MESSAGE_PROXY_FAILED",
message: "Failed to create appeal complete message"
});
});
});
+13 -3
View File
@@ -8,6 +8,7 @@ import { getCaseBlob, createBlob } from "../../../actions/azurestorage";
import { getTempCaseRef } from "../../../components/utils";
import { v4 as uuidv4 } from "uuid";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const WEBAPI_URL =
process.env.RELAY_ROOT ||
@@ -33,7 +34,12 @@ export default async function ApiProxy(req, res) {
typeof lpaID === "undefined" ||
lpaID.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message:
"contactid, appealTypeId, containername and lpaID are required"
});
}
var data = {
@@ -73,10 +79,14 @@ export default async function ApiProxy(req, res) {
// data: JSON.stringify(newData),
// };
var apiResponse = _.isEmpty(req.query)
? res.status(400).json()
? respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "Query parameters are required"
})
: (getCaseBlob(containerName, tempCaseRef, newData),
createBlob(JSON.stringify(newAppealObj), containerName),
res.status(200).json(newData));
respondSuccess(res, newData));
return apiResponse;
}
+13 -4
View File
@@ -15,6 +15,7 @@ import CryptoJS from "crypto-js";
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 ||
@@ -28,7 +29,11 @@ export default async function ApiProxy(req, res) {
typeof req.body.incidentid === "undefined" ||
req.body.incidentid.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_BODY",
message: "contactid and incidentid are required"
});
}
var token = await getToken();
@@ -61,12 +66,16 @@ export default async function ApiProxy(req, res) {
return axios(config)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
return error.status == 412
? res.status(200).json({ "record": "exists" })
? respondSuccess(res, { "record": "exists" })
: (consoleLogger(Object.assign(error, data)),
res.status(400).json(error));
respondError(res, {
status: 400,
code: "CREATE_CASE_INVOLVEMENT_FAILED",
message: "Failed to create case involvement"
}));
});
}
+17 -4
View File
@@ -4,6 +4,7 @@ import {
} from "../../../actions/azurestorage";
import { hashAPIPath } from "../../../actions/core/hash";
import { consoleLogger } from "../../../actions/core/logger";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -27,7 +28,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, tempcaseref, repid and hash are required"
});
}
var checkquerypath =
@@ -39,16 +44,24 @@ ApiProxy.get(async (req, res) => {
filename;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await createRepCompleteMessage(containerName, tempCaseRef, filename)
.then((data) => {
return res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
return res.status(400).json();
return respondError(res, {
status: 400,
code: "CREATE_REP_COMPLETE_MESSAGE_FAILED",
message: "Failed to create representation complete message"
});
});
});
+13 -4
View File
@@ -15,6 +15,7 @@ import CryptoJS from "crypto-js";
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 ||
@@ -28,7 +29,11 @@ export default async function ApiProxy(req, res) {
typeof req.body.incidentid === "undefined" ||
req.body.incidentid.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_BODY",
message: "contactid and incidentid are required"
});
}
var token = await getToken();
@@ -63,12 +68,16 @@ export default async function ApiProxy(req, res) {
return axios(config)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
return error.status == 412
? res.status(200).json({ "record": "exists" })
? respondSuccess(res, { "record": "exists" })
: (consoleLogger(Object.assign(error, data)),
res.status(400).json(error));
respondError(res, {
status: 400,
code: "CREATE_REP_INVOLVEMENT_FAILED",
message: "Failed to create representation involvement"
}));
});
}
@@ -1,5 +1,6 @@
import { hashAPIPath } from "../../../actions/core/hash";
import { deleteBlob } from "../../../actions/azurestorage";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -23,7 +24,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID, blobname and hash are required"
});
}
var checkquerypath =
@@ -35,12 +40,16 @@ ApiProxy.get(async (req, res) => {
blobName;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await deleteBlob(containerName, casefolderID + "/files/" + blobName).then(
(data) => {
return res.status(200).json({ data: data });
return respondSuccess(res, { data: data });
}
);
});
+12 -3
View File
@@ -1,5 +1,6 @@
import { hashAPIPath } from "../../../actions/core/hash";
import { deleteBlob } from "../../../actions/azurestorage";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -23,7 +24,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID, blobname and hash are required"
});
}
var checkquerypath =
@@ -35,12 +40,16 @@ ApiProxy.get(async (req, res) => {
encodeURIComponent(blobName);
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await deleteBlob(containerName, casefolderID + "/files/" + blobName).then(
(data) => {
return res.status(200).json({ data: data });
return respondSuccess(res, { data: data });
}
);
});
+14 -7
View File
@@ -1,5 +1,6 @@
import { hashAPIPath } from "../../../actions/core/hash";
import { deleteBlobCase } from "../../../actions/azurestorage";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -20,7 +21,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID and hash are required"
});
}
var checkquerypath =
@@ -30,14 +35,16 @@ ApiProxy.get(async (req, res) => {
casefolderID;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
}
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
await deleteBlobCase(containerName, casefolderID).then((data) => {
return res.status(200).json({ data: data });
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await deleteBlobCase(containerName, casefolderID).then((data) => {
return respondSuccess(res, { data: data });
});
});
export const config = {
+14 -7
View File
@@ -1,5 +1,6 @@
import { hashAPIPath } from "../../../actions/core/hash";
import { deleteBlobRep } from "../../../actions/azurestorage";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -23,7 +24,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID, repfile and hash are required"
});
}
var checkquerypath =
@@ -35,16 +40,18 @@ ApiProxy.get(async (req, res) => {
repfile;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
casefolderID = casefolderID + "/" + repfile;
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
await deleteBlobRep(containerName, casefolderID).then((data) => {
return res.status(200).json({ data: data });
});
}
await deleteBlobRep(containerName, casefolderID).then((data) => {
return respondSuccess(res, { data: data });
});
});
export const config = {
+22 -15
View File
@@ -3,6 +3,7 @@ import { downloadFile } from "../../../actions/azurestorage";
import nextConnect from "next-connect";
import { hashAPIPath } from "../../../actions/core/hash";
import middleware from "../middleware/middleware";
import { respondError } from "../middleware/apiResponse";
const ApiProxy = nextConnect();
@@ -24,7 +25,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID, blobname and hash are required"
});
}
var checkquerypath =
@@ -36,24 +41,26 @@ ApiProxy.get(async (req, res) => {
blobName.trim();
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
const bloblocation =
casefolderID + (blobName.indexOf(".json") > 0 ? "/" : "/files/");
const bloblocation =
casefolderID + (blobName.indexOf(".json") > 0 ? "/" : "/files/");
const downloaded = await downloadFile(
containerName,
bloblocation + decodeURI(blobName)
);
const downloaded = await downloadFile(
containerName,
bloblocation + decodeURI(blobName)
);
res.setHeader(
"content-disposition",
"attachment; filename=" + decodeURI(blobName)
);
return res.status(200).send(downloaded);
}
res.setHeader(
"content-disposition",
"attachment; filename=" + decodeURI(blobName)
);
return res.status(200).send(downloaded);
});
async function streamToBuffer(readableStream) {
+21 -7
View File
@@ -1,17 +1,25 @@
import { DefaultAzureCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
import { consoleLogger } from "../../../actions/core/logger";
import { respondError, respondSuccess } from "../middleware/apiResponse";
export default async function handler(req, res) {
if (req.method !== "POST") {
res.status(405).json({ error: "Method not allowed" });
return;
return respondError(res, {
status: 405,
code: "METHOD_NOT_ALLOWED",
message: "Method not allowed"
});
}
const { container, blobName } = req.body;
if (!container || !blobName) {
res.status(400).json({ error: "Missing container or blobName" });
return;
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_BODY",
message: "Missing container or blobName"
});
}
try {
@@ -60,10 +68,16 @@ export default async function handler(req, res) {
const withTags = await blockBlobClient.setTags(tags);
const withMeta = await blockBlobClient.setMetadata(tags);
res.status(200).json({ message: "repComplete removed successfully" });
return respondSuccess(res, {
message: "repComplete removed successfully"
});
} catch (error) {
console.error("Error editing rep.json:", error);
res.status(500).json({ error: "Failed to edit rep.json" });
consoleLogger(error);
return respondError(res, {
status: 500,
code: "EDIT_REP_JSON_FAILED",
message: "Failed to edit rep.json"
});
}
}
+35 -17
View File
@@ -104,6 +104,7 @@ import { finalComments_pdf } from "../../../components/pdftemplates/finalComment
import { statement_pdf } from "../../../components/pdftemplates/statement_pdf";
import { writtenStatement_pdf } from "../../../components/pdftemplates/writtenStatement_pdf";
import { other_pdf } from "../../../components/pdftemplates/other_pdf";
import { respondError, respondSuccess } from "../middleware/apiResponse";
//const ApiProxy = nextConnect();
// ApiProxy.use(middleware);
@@ -132,7 +133,12 @@ export default async function handler(req, res) {
typeof casefolderID === "undefined" ||
String(casefolderID).length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message:
"hash, appealType, containerID and casefolderID are required"
});
}
checkquerypath =
@@ -142,7 +148,11 @@ export default async function handler(req, res) {
(isDownload ? "&download=true" : "");
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
// Create Document Component
@@ -238,20 +248,28 @@ export default async function handler(req, res) {
renderedPDFBuffer,
containerID,
blobProgress.pinswg_name || blobProgress.caseObj.ticketnumber
).then((data) => {
if (isDownload) {
const filename = `${pdfFileName}.pdf`;
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
"Content-Disposition",
`attachment; filename="${filename}"`
);
return res.status(200).send(renderedPDFBuffer);
}
return res.status(200).json({
status: "success",
data: data,
path: `/files/${pdfFileName}.pdf`
)
.then((data) => {
if (isDownload) {
const filename = `${pdfFileName}.pdf`;
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
"Content-Disposition",
`attachment; filename="${filename}"`
);
return res.status(200).send(renderedPDFBuffer);
}
return respondSuccess(res, {
status: "success",
data: data,
path: `/files/${pdfFileName}.pdf`
});
})
.catch(() => {
return respondError(res, {
status: 400,
code: "GENERATE_APPEAL_PDF_FAILED",
message: "Failed to generate appeal PDF"
});
});
});
}
+17 -4
View File
@@ -101,6 +101,7 @@ import { statement_pdf } from "../../../components/pdftemplates/statement_pdf";
import { writtenStatement_pdf } from "../../../components/pdftemplates/writtenStatement_pdf";
import { other_pdf } from "../../../components/pdftemplates/other_pdf";
import { consoleLogger } from "../../../actions/core/logger";
import { respondError, respondSuccess } from "../middleware/apiResponse";
//const ApiProxy = nextConnect();
// ApiProxy.use(middleware);
@@ -183,14 +184,22 @@ export default async function handler(req, res) {
}
if (typeof checkHash === "undefined" || checkHash.length === 0) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "HASH_REQUIRED",
message: "hash is required"
});
}
if (
hashAPIPath(checkquerypath) !=
(checkquerypath.indexOf("?") > -1 ? "&hash=" : "?hash=") + checkHash
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
//console.log("-------", checkHash);
@@ -349,7 +358,7 @@ export default async function handler(req, res) {
return res.status(200).send(renderedPDFBuffer);
}
return res.status(200).json({
return respondSuccess(res, {
status: "success",
data: data,
path: `${caseRef}/${reqBodyobj.repfile_name}/files/${reqBodyobj.repfile_name}.pdf`
@@ -357,6 +366,10 @@ export default async function handler(req, res) {
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "GENERATE_PDF_FAILED",
message: "Failed to generate PDF"
});
});
}
+18 -11
View File
@@ -6,6 +6,7 @@ import _ from "lodash";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
@@ -20,25 +21,31 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container and hash are required"
});
}
var checkquerypath =
"/api/file/getawaitingsubmissionfromblob?container=" + containerName;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
const blobObj = await getAllProgressBlobs(containerName)
.then((data) => {
return downloadAllProgressFiles(containerName, data);
})
.then((data) => {
return res.status(200).json(data);
});
}
const blobObj = await getAllProgressBlobs(containerName)
.then((data) => {
return downloadAllProgressFiles(containerName, data);
})
.then((data) => {
return respondSuccess(res, data);
});
});
export const config = {
@@ -3,6 +3,7 @@ import { azureHeaders } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger";
import { hashAPIPath } from "../../../actions/core/hash";
import axios from "axios";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
@@ -13,7 +14,11 @@ export default async function ApiProxy(req, res) {
var containerName = req.query.container;
if (!hasValue(containerName)) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container is required"
});
}
var token = await getToken();
@@ -27,10 +32,14 @@ export default async function ApiProxy(req, res) {
azureHeaders(token.access_token)
)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "GET_AWAITING_SUBMISSION_PROXY_FAILED",
message: "Failed to fetch awaiting submission blob"
});
});
}
+21 -13
View File
@@ -31,6 +31,7 @@
import { hashAPIPath } from "../../../actions/core/hash";
import { getBlobs, getRepsFilesBlobs } from "../../../actions/azurestorage";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -52,7 +53,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID and hash are required"
});
}
var checkquerypath =
@@ -62,20 +67,23 @@ ApiProxy.get(async (req, res) => {
casefolderID;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
casefolderID.split("/").length > 1
? await getRepsFilesBlobs(
containerName,
casefolderID.split("/")[0],
casefolderID.split("/")[1]
).then((data) => {
return res.status(200).json({ "value": [data] });
})
: await getBlobs(containerName, casefolderID).then((data) => {
return res.status(200).json({ "value": [data] });
});
const data =
casefolderID.split("/").length > 1
? await getRepsFilesBlobs(
containerName,
casefolderID.split("/")[0],
casefolderID.split("/")[1]
)
: await getBlobs(containerName, casefolderID);
return respondSuccess(res, { "value": [data] });
});
export const config = {
+12 -3
View File
@@ -3,6 +3,7 @@ import { azureHeaders } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger";
import { hashAPIPath } from "../../../actions/core/hash";
import axios from "axios";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
@@ -14,7 +15,11 @@ export default async function ApiProxy(req, res) {
var casefolderID = req.query.casefolderID;
if (!hasValue(containerName) || !hasValue(casefolderID)) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container and casefolderID are required"
});
}
var token = await getToken();
@@ -31,10 +36,14 @@ export default async function ApiProxy(req, res) {
azureHeaders(token.access_token)
)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "GET_BLOB_LIST_PROXY_FAILED",
message: "Failed to fetch blob list"
});
});
}
+12 -3
View File
@@ -6,6 +6,7 @@ import _ from "lodash";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
@@ -24,7 +25,11 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container, casefolderID and hash are required"
});
}
var checkquerypath =
@@ -34,7 +39,11 @@ ApiProxy.get(async (req, res) => {
casefolderID;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await getProgressBlobs(containerName, casefolderID)
@@ -42,7 +51,7 @@ ApiProxy.get(async (req, res) => {
return downloadProgressFile(containerName, data.path, casefolderID);
})
.then((data) => {
return res.status(200).json(data);
return respondSuccess(res, data);
});
});
+27 -18
View File
@@ -38,6 +38,7 @@ import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
import { hashAPIPath } from "../../../actions/core/hash";
import { consoleLogger } from "../../../actions/core/logger";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
@@ -54,32 +55,40 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container and hash are required"
});
}
var checkquerypath = "/api/file/getrepsblob?container=" + containerName;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
const blobObj = await getRepsBlobs(containerName)
.then(async (data) => {
return data;
})
.then(async (data) => {
let result = await downloadAllRepsFiles(containerName, data);
return res
.setHeader("Cache-Control", "no-store")
.status(200)
.json(result);
})
.catch((error) => {
consoleLogger(error);
const blobObj = await getRepsBlobs(containerName)
.then(async (data) => {
return data;
})
.then(async (data) => {
let result = await downloadAllRepsFiles(containerName, data);
res.setHeader("Cache-Control", "no-store");
return respondSuccess(res, result);
})
.catch((error) => {
consoleLogger(error);
return respondError(res, {
status: 400,
code: "GET_REPS_BLOB_FAILED",
message: "Failed to retrieve representation blobs"
});
}
});
});
export default ApiProxy;
+12 -3
View File
@@ -3,6 +3,7 @@ import { azureHeaders } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger";
import { hashAPIPath } from "../../../actions/core/hash";
import axios from "axios";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
@@ -13,7 +14,11 @@ export default async function ApiProxy(req, res) {
var containerName = req.query.container;
if (!hasValue(containerName)) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "container is required"
});
}
var token = await getToken();
@@ -26,10 +31,14 @@ export default async function ApiProxy(req, res) {
azureHeaders(token.access_token)
)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "GET_REPS_BLOB_PROXY_FAILED",
message: "Failed to fetch representation blobs"
});
});
}
+17 -4
View File
@@ -7,6 +7,7 @@ import {
} from "../../../actions/azurestorage";
import { hashAPIPath } from "../../../actions/core/hash";
import { consoleLogger } from "../../../actions/core/logger";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import middleware from "../middleware/middleware";
import nextConnect from "next-connect";
@@ -24,22 +25,34 @@ ApiProxy.get(async (req, res) => {
typeof checkHash === "undefined" ||
checkHash.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message: "ident and hash are required"
});
}
var checkquerypath = "/api/file/setupcontainer?ident=" + containerName;
if (hashAPIPath(checkquerypath) != "&hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
await createContainer(containerName)
.then((data) => {
return res.status(200).json({ data: "success", output: data });
return respondSuccess(res, { data: "success", output: data });
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "SETUP_CONTAINER_FAILED",
message: "Failed to setup container"
});
});
});
+13 -3
View File
@@ -3,6 +3,7 @@ import CryptoJS from "crypto-js";
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 ||
@@ -26,7 +27,12 @@ export default async function ApiProxy(req, res) {
typeof req.body === "undefined" ||
req.body === null
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_QUERY",
message:
"updateFormCollection, appealObj, incident and body are required"
});
}
var token = await getToken();
@@ -49,10 +55,14 @@ export default async function ApiProxy(req, res) {
return axios(config)
.then(({ data }) => {
res.status(200).json(data);
return respondSuccess(res, data);
})
.catch((error) => {
consoleLogger(error);
res.status(400).json(error);
return respondError(res, {
status: 400,
code: "UPDATE_CASE_FAILED",
message: "Failed to update case"
});
});
}
+31 -22
View File
@@ -4,6 +4,7 @@ import {
uploadFile
} from "../../../actions/azurestorage";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
@@ -15,13 +16,21 @@ ApiProxy.post(async (req, res) => {
var checkHash = req.query.hash;
if (typeof checkHash === "undefined" || checkHash.length === 0) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "HASH_REQUIRED",
message: "hash is required"
});
}
var checkquerypath = "/api/file/upload";
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
const appealData = req.body.appealData;
@@ -35,28 +44,28 @@ ApiProxy.post(async (req, res) => {
typeof casefolderID === "undefined" ||
casefolderID.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_BODY",
message: "containerID and casefolderID are required"
});
}
repOrAppeal
? createRepBlob(appealData, containerID, casefolderID).then((data) => {
// Object.keys(req.files).length > 0 &&
// uploadFile(req.files, containerID, casefolderID).then(
// (data) => {
// return res.status(200).json({ data });
// }
// );
return res.status(200).json({ data });
})
: createBlob(appealData, containerID, casefolderID).then((data) => {
// Object.keys(req.files).length > 0 &&
// uploadFile(req.files, containerID, casefolderID).then(
// (data) => {
// return res.status(200).json({ data });
// }
// );
return res.status(200).json({ data });
});
return (
repOrAppeal
? createRepBlob(appealData, containerID, casefolderID)
: createBlob(appealData, containerID, casefolderID)
)
.then((data) => {
return respondSuccess(res, { data });
})
.catch(() => {
return respondError(res, {
status: 400,
code: "UPLOAD_FAILED",
message: "Failed to upload blob"
});
});
});
export const config = {
+22 -5
View File
@@ -8,6 +8,7 @@ import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
import { consoleLogger } from "../../../actions/core/logger";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
import { fileTypeFromBuffer } from "file-type";
import fs from "fs";
import path from "path";
@@ -39,13 +40,21 @@ ApiProxy.post(async (req, res) => {
var checkHash = req.query.hash;
if (typeof checkHash === "undefined" || checkHash.length === 0) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "HASH_REQUIRED",
message: "hash is required"
});
}
var checkquerypath = "/api/file/uploadsinglefile";
if (hashAPIPath(checkquerypath) != "?hash=" + checkHash) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "INVALID_HASH",
message: "Invalid hash"
});
}
const containerID = req.body?.containerID?.[0];
@@ -57,7 +66,11 @@ ApiProxy.post(async (req, res) => {
typeof casefolderID === "undefined" ||
casefolderID.length === 0
) {
return res.status(400).json();
return respondError(res, {
status: 400,
code: "MISSING_REQUIRED_BODY",
message: "containerID and casefolderID are required"
});
}
const uploadedFiles = req.files || {};
@@ -126,10 +139,14 @@ ApiProxy.post(async (req, res) => {
containerID,
casefolderID
);
return res.status(200).json({ data, invalidFiles });
return respondSuccess(res, { data, invalidFiles });
} catch (error) {
consoleLogger(error);
return res.status(500).json({ error: "Failed to upload files" });
return respondError(res, {
status: 500,
code: "UPLOAD_SINGLE_FILE_FAILED",
message: "Failed to upload files"
});
}
});
+28
View File
@@ -0,0 +1,28 @@
export const respondSuccess = (res, data, status = 200) => {
return res.status(status).json(data);
};
export const respondError = (
res,
{
status = 500,
code = "INTERNAL_SERVER_ERROR",
message = "Request failed",
details
} = {}
) => {
const isProduction = process.env.NODE_ENV === "production";
const payload = {
success: false,
error: {
code,
message
}
};
if (!isProduction && typeof details !== "undefined") {
payload.error.details = details;
}
return res.status(status).json(payload);
};