Merged PR 2009: partial synch with ph2 updates

partial synch with ph2 updates

Related work items: #20553
This commit is contained in:
Robert Bond
2025-11-28 08:50:01 +00:00
34 changed files with 1425 additions and 471 deletions
+36 -35
View File
@@ -54,10 +54,10 @@ const StoragePage = (props) => {
{/* Tabs */}
<ul className="govuk-tabs__list">
{[
"documents",
"appeals",
"storage",
"accounts",
"appeals",
"documents",
].map((tab) => (
<li
key={tab}
@@ -76,20 +76,50 @@ const StoragePage = (props) => {
props.setCurrentPage(1);
}}
>
{" "}
{tab === "documents" &&
"Latest Documents"}
{tab === "appeals" &&
"Latest Appeals"}
{tab === "storage" &&
"Storage Account"}
{tab === "accounts" &&
"User Accounts"}
{tab === "appeals" &&
"Latest Appeals"}
{tab === "documents" &&
"Latest Documents"}
</a>
</li>
))}
</ul>
{/* Panels */}
<div
className={
whichTab === "documents"
? "govuk-tabs__panel"
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
>
<DocumentsTab
documentDetailsObj={
props.searchResultsObj
.documentDetailsObj
}
docsOffline={docsOffline}
showFilteredDocs={props.showFilteredDocs}
/>
</div>
<div
className={
whichTab === "appeals"
? "govuk-tabs__panel"
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
>
<AppealsTab
searchResultsObj={searchResultsObj}
/>
</div>
<div
className={
whichTab === "storage"
@@ -112,35 +142,6 @@ const StoragePage = (props) => {
>
<AccountsTab userData={userData} />
</div>
<div
className={
whichTab === "appeals"
? "govuk-tabs__panel"
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
>
<AppealsTab
searchResultsObj={searchResultsObj}
/>
</div>
<div
className={
whichTab === "documents"
? "govuk-tabs__panel"
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
>
<DocumentsTab
documentDetailsObj={
props.searchResultsObj
.documentDetailsObj
}
docsOffline={docsOffline}
showFilteredDocs={props.showFilteredDocs}
/>
</div>
</div>
</div>
</div>
+3 -3
View File
@@ -124,8 +124,8 @@ export const getServerSideProps = wrapper.getServerSideProps(
// "=============================== Advanced Search results:",
// searchResultsObj
// );
const searchDetailsObj =
(await getSearchDetails(searchResultsObj)) || null;
// const searchDetailsObj =
// (await getSearchDetails(searchResultsObj)) || null;
// console.log(
// "=============================== Advanced Search results details:",
// searchDetailsObj
@@ -136,7 +136,7 @@ export const getServerSideProps = wrapper.getServerSideProps(
store.dispatch(setShowReps(showReps, showLoginCheck));
store.dispatch(setSearchResults(searchResultsObj));
store.dispatch(setSearchDetails(searchDetailsObj));
// store.dispatch(setSearchDetails(searchDetailsObj));
store.dispatch(setSearch(Object.entries(query)));
return {
props: {
+25 -1
View File
@@ -64,9 +64,11 @@ export default async function ApiProxy(req, res) {
var fieldSort = req.query.fieldSort || "desc";
var showNumberOfRecords = req.query.showNumberOfRecords || 10;
var documentType = req.query.documentType || "all";
var documentOrigin = req.query.documentOrigin || "all";
var numberOfWeeks = req.query.numberWeeks || 1;
var docTypeQueryString = "";
var docOriginQueryString = "";
if (documentType != "all") {
if (documentType.indexOf(",") >= 0) {
@@ -91,6 +93,27 @@ export default async function ApiProxy(req, res) {
}
}
if (documentOrigin != "all") {
if (documentOrigin.indexOf(",") >= 0) {
const documentOriginArr = documentOrigin.split(",");
docOriginQueryString = " and (";
documentOriginArr.forEach(function (item, index) {
console.log(item, index);
if (item != "all") {
docOriginQueryString += " pinswg_origin eq " + item;
docOriginQueryString +=
index < documentOriginArr.length - 1 ? " or " : "";
}
});
docOriginQueryString += " )";
} else {
docOriginQueryString += " and pinswg_origin eq " + documentOrigin;
}
}
function daysAgoISO(days) {
const today = new Date();
const resultDate = new Date(today);
@@ -103,6 +126,7 @@ export default async function ApiProxy(req, res) {
"pinswg_documents?$select=pinswg_name,createdon,pinswg_publishtoweb,_pinswg_documentids_value,pinswg_isharedocumentlocations,pinswg_isharedocumentreference,pinswg_uploadurl,pinswg_uploadstatus,pinswg_origin&$filter=createdon ge " +
daysAgoISO(numberOfWeeks) +
docTypeQueryString +
docOriginQueryString +
"&$orderby=" +
orderby +
" " +
@@ -115,7 +139,7 @@ export default async function ApiProxy(req, res) {
console.log(
"\n==========================================\n",
"\nnew docs search ",
"\nnew docs search---- ",
"\n\nQuery url: " + queryUrl,
"\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
"\n==========================================\n"
+194 -101
View File
@@ -1,110 +1,203 @@
/**
* @swagger
* /api/documents/download/{id}:
* get:
* tags:
* - Documents
* description: Get document
* parameters:
* - name: id
* in: path
* description: iShare ID
* type: string
* required: true
* default: A41567436
* - name: hash
* in: query
* description: Hash string
* default: e0a1c9cd2817826a25bca67e60b807eae747cbed769e3ec42cf997541c32be71
* responses:
* 200:
* description: Success
*/
// /**
// * @swagger
// * /api/documents/download/{id}:
// * get:
// * tags:
// * - Documents
// * description: Get document
// * parameters:
// * - name: id
// * in: path
// * description: iShare ID
// * type: string
// * required: true
// * default: A41567436
// * - name: hash
// * in: query
// * description: Hash string
// * default: e0a1c9cd2817826a25bca67e60b807eae747cbed769e3ec42cf997541c32be71
// * responses:
// * 200:
// * description: Success
// */
// import axios from "axios";
// import CryptoJS from "crypto-js";
// import { getToken, consoleLogger } from "../../../../actions";
// const WORDKEY = process.env.HASHKEY;
// const accessTokenEndpoint = process.env.ACCESS_TOKEN_ENDPOINT;
// const tenantId = process.env.TENANT;
// const WEBAPI_URL =
// process.env.RELAY_ROOT ||
// "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
// const hashAPIPath = (queryPath) => {
// var hashlink = CryptoJS.HmacSHA256(
// queryPath,
// CryptoJS.enc.Hex.parse(WORDKEY)
// );
// hashlink = hashlink.toString(CryptoJS.enc.Hex);
// //return "&hash=" + hashlink;
// return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink;
// };
// const azureHeadersPaged = (access_token) => {
// return {
// headers: {
// "OData-MaxVersion": "4.0",
// "OData-Version": "4.0",
// "Accept": "application/json;odata.metadata=none",
// "Prefer":
// 'odata.include-annotations="*",return=representation, odata.maxpagesize=10',
// "Content-Type": "application/json",
// "Authorization": "Bearer " + access_token,
// },
// };
// };
// export default async function ApiProxy(req, res) {
// var token = await getToken();
// var docRef = req.query;
// var queryUrl = "documents/download/" + docRef.id + "?hash=" + docRef.hash;
// const configDocument = (access_token) => {
// return {
// headers: {
// "OData-MaxVersion": "4.0",
// "OData-Version": "4.0",
// "Accept": "application/json",
// "Prefer": 'odata.include-annotations="*",return=representation',
// "Content-Type": "application/json",
// "Authorization": "Bearer " + access_token,
// },
// responseType: "arraybuffer",
// };
// };
// return axios
// .get(
// WEBAPI_URL + queryUrl, // + hashAPIPath(queryUrl),
// configDocument(token.access_token)
// )
// .then((response) => {
// const bytes = response.data.byteLength;
// console.log(bytes);
// res.setHeader(
// "content-disposition",
// "attachment; filename=" +
// response.headers["content-disposition"].split(
// "filename="
// )[1]
// );
// return res.status(200).send(response.data);
// })
// .then(() => {
// console.log(docRef.id + "has downloaded");
// return "downloadComplete";
// })
// .catch((error) => {
// consoleLogger(error);
// res.redirect("/filenotavailable");
// });
// }
import axios from "axios";
import CryptoJS from "crypto-js";
import { getToken, consoleLogger } from "../../../../actions";
const WORDKEY = process.env.HASHKEY;
const accessTokenEndpoint = process.env.ACCESS_TOKEN_ENDPOINT;
const tenantId = process.env.TENANT;
const WEBAPI_URL =
process.env.RELAY_ROOT ||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
const hashAPIPath = (queryPath) => {
var hashlink = CryptoJS.HmacSHA256(
queryPath,
CryptoJS.enc.Hex.parse(WORDKEY)
);
hashlink = hashlink.toString(CryptoJS.enc.Hex);
//return "&hash=" + hashlink;
return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink;
};
const azureHeadersPaged = (access_token) => {
return {
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Accept": "application/json;odata.metadata=none",
"Prefer":
'odata.include-annotations="*",return=representation, odata.maxpagesize=10',
"Content-Type": "application/json",
"Authorization": "Bearer " + access_token,
},
};
};
export default async function ApiProxy(req, res) {
var token = await getToken();
var docRef = req.query;
var queryUrl = "documents/download/" + docRef.id + "?hash=" + docRef.hash;
const configDocument = (access_token) => {
return {
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Accept": "application/json",
"Prefer": 'odata.include-annotations="*",return=representation',
"Content-Type": "application/json",
"Authorization": "Bearer " + access_token,
},
responseType: "arraybuffer",
};
};
return axios
.get(
WEBAPI_URL + queryUrl, // + hashAPIPath(queryUrl),
configDocument(token.access_token)
)
.then((response) => {
const bytes = response.data.byteLength;
console.log(bytes);
res.setHeader(
"content-disposition",
"attachment; filename=" +
response.headers["content-disposition"].split(
"filename="
)[1]
);
return res.status(200).send(response.data);
})
.then(() => {
console.log(docRef.id + "has downloaded");
return "downloadComplete";
})
.catch((error) => {
consoleLogger(error);
res.redirect("/filenotavailable");
});
// Retry utility with logging
async function retry(fn, retries = 3, delay = 1000) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
return { response: await fn(), attempts: attempt };
} catch (err) {
if (attempt === retries) throw err;
console.log(`Retry ${attempt} failed, retrying in ${delay}ms...`);
await new Promise((res) => setTimeout(res, delay));
delay *= 2; // exponential backoff
}
}
}
const ApiProxy = async (req, res) => {
const docRef = req.query;
try {
const token = await getToken();
const startTime = Date.now();
const fetchStream = async () => {
const queryUrl =
"documents/download/" + docRef.id + "?hash=" + docRef.hash;
return axios.get(WEBAPI_URL + queryUrl, {
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Accept": "application/json",
"Prefer":
'odata.include-annotations="*",return=representation',
"Content-Type": "application/json",
"Authorization": "Bearer " + token.access_token,
},
responseType: "stream",
});
};
const { response, attempts } = await retry(fetchStream, 3, 1000);
// Extract filename
const contentDisposition = response.headers["content-disposition"];
const filename = contentDisposition
? contentDisposition.split("filename=")[1]
: docRef.id;
res.setHeader(
"Content-Disposition",
`attachment; filename=${filename}`
);
res.setHeader("Content-Type", "application/octet-stream");
let totalBytes = 0;
response.data.on("data", (chunk) => {
totalBytes += chunk.length;
});
response.data.pipe(res);
response.data.on("end", () => {
const durationMs = Date.now() - startTime;
console.log(
`[Download Complete] Document: ${filename}, ID: ${docRef.id}, Size: ${totalBytes} bytes, Duration: ${durationMs}ms, Attempts: ${attempts}`
);
});
response.data.on("error", (err) => {
consoleLogger(err);
if (!res.headersSent) res.redirect("/filenotavailable");
});
} catch (error) {
consoleLogger(error);
if (!res.headersSent) res.redirect("/filenotavailable");
}
};
export const config = {
api: {
responseLimit: false,
},
};
export default ApiProxy;
@@ -64,13 +64,16 @@ export default async function ApiProxy(req, res) {
primaryIdAttribute
).NavigationProperty;
// "?$filter=_" +
// (primaryIdAttribute == "pinswg_sipscase"
// ? "pinswg_sipscase_value"
// : primaryIdAttribute + "s_value ") +
// " eq " +
// incidentID +
var queryUrl =
appealTypeName +
"?$filter=_" +
(primaryIdAttribute == "pinswg_sipscase"
? "pinswg_sipscase_value"
: primaryIdAttribute + "s_value ") +
" eq " +
"?$filter=" +
incidentID +
"&$count=true" +
"&$expand=" +
+30 -27
View File
@@ -124,38 +124,41 @@ export const getServerSideProps = wrapper.getServerSideProps(
"public, s-maxage=10, stale-while-revalidate=59"
);
let searchResultsObj = await getBasicDNSSearch();
// let searchResultsObj = await getBasicDNSSearch();
searchResultsObj =
searchResultsObj.status == 502
? {
value: [],
errorCode: searchResultsObj.status,
errorMsg: searchResultsObj.statusText,
}
: searchResultsObj;
// searchResultsObj =
// searchResultsObj.status == 502
// ? {
// value: [],
// errorCode: searchResultsObj.status,
// errorMsg: searchResultsObj.statusText,
// }
// : searchResultsObj;
const showLoginCheck = process.env.SHOWLOGIN || false;
const showMapCheck = process.env.SHOWMAPS || false;
if (_.has(searchResultsObj, "status") == true) {
return {
redirect: {
//destination: "/dns-not-found",
destination: "/error",
permanent: false,
},
};
} else {
const searchDetailsObj = await getSearchDetails(
searchResultsObj
);
const dnsCoords = await getDNSCoords();
store.dispatch(setSearchResults(searchResultsObj));
store.dispatch(setSearchDetails(searchDetailsObj));
store.dispatch(setSearch("DNS"));
store.dispatch(setDNSCoords(dnsCoords));
}
// if (_.has(searchResultsObj, "status") == true) {
// return {
// redirect: {
// //destination: "/dns-not-found",
// destination: "/error",
// permanent: false,
// },
// };
// } else {
// // const searchDetailsObj = await getSearchDetails(
// // searchResultsObj
// // );
// const dnsCoords = await getDNSCoords();
// // store.dispatch(setSearchResults(searchResultsObj));
// // store.dispatch(setSearchDetails(searchDetailsObj));
// store.dispatch(setSearch("DNS"));
// store.dispatch(setDNSCoords(dnsCoords));
// }
const dnsCoords = await getDNSCoords();
store.dispatch(setSearch("DNS"));
store.dispatch(setDNSCoords(dnsCoords));
return {
props: {
+7 -8
View File
@@ -106,8 +106,11 @@ const CaseHome = (props) => {
props.awaitingSubmission.awaitingSubmission
}
caseReference={
props.searchResultsObj.searchResultsObj.value[0]
.ticketnumber
props.currentView.caseReference.currentReference
}
ticketnumber={
props.currentView.caseReference.ticketnumber ||
router.query.ticketnumber
}
ticketnumber={
props.currentView.caseReference.ticketnumber ||
@@ -115,13 +118,9 @@ const CaseHome = (props) => {
}
currentType={props.currentType}
appealTypeID={
props.searchResultsObj.searchResultsObj.value[0]
.pinswg_appealcasetype
}
incidentid={
props.searchResultsObj.searchResultsObj.value[0]
.incidentid
props.currentView.caseReference.appealType
}
incidentid={props.currentView.caseReference.incidentid}
representationsObj={
props.searchResultsObj.representationsObj
}
+4 -1
View File
@@ -58,9 +58,10 @@ const Home = (props) => {
showLoginCheck,
currentView,
mySubmittedReps,
docsOffline,
} = props;
const { t } = useTranslation();
let { t, lang } = useTranslation();
const router = useRouter();
const { locale, query } = router;
const { appealtypes } = query;
@@ -150,6 +151,7 @@ const Home = (props) => {
containerID={accountDetails.containerID}
showLoginCheck={showLoginCheck}
currentView={currentView}
docsOffline={docsOffline}
/>
</div>
<Footer footerLinks={footerLinks} ticketnumber={props} />
@@ -357,6 +359,7 @@ export const getServerSideProps = wrapper.getServerSideProps(
showFileUpload: Boolean(process.env.SHOWFILEUPLOAD),
containerID: thisSession.user.id,
showLoginCheck,
docsOffline: process.env.DOCAPI_OFFLINE || false,
},
};
}
+24 -23
View File
@@ -132,33 +132,34 @@ export const getServerSideProps = wrapper.getServerSideProps(
const showReps = process.env.SHOWREPRESENTATIONS || false;
store.dispatch(setShowReps(showReps, showLoginCheck));
let searchResultsObj = await getBasicSearch(query.q);
// let searchResultsObj = await getBasicSearch(query.q);
searchResultsObj =
searchResultsObj.status == 502
? {
value: [],
errorCode: searchResultsObj.status,
errorMsg: searchResultsObj.statusText,
}
: searchResultsObj;
// searchResultsObj =
// searchResultsObj.status == 502
// ? {
// value: [],
// errorCode: searchResultsObj.status,
// errorMsg: searchResultsObj.statusText,
// }
// : searchResultsObj;
if (_.has(searchResultsObj, "status") == true) {
return {
redirect: {
//destination: "/dns-not-found",
destination: "/error",
permanent: false,
},
};
} else {
const searchDetailsObj = await getSearchDetails(searchResultsObj);
// if (_.has(searchResultsObj, "status") == true) {
// return {
// redirect: {
// //destination: "/dns-not-found",
// destination: "/error",
// permanent: false,
// },
// };
// } else {
// // const searchDetailsObj = await getSearchDetails(searchResultsObj);
store.dispatch(setSearchResults(searchResultsObj));
store.dispatch(setSearchDetails(searchDetailsObj));
store.dispatch(setSearch(query.q));
}
// store.dispatch(setSearchResults(searchResultsObj));
// // store.dispatch(setSearchDetails(searchDetailsObj));
// store.dispatch(setSearch(query.q));
// }
store.dispatch(setSearch(query.q));
return {
props: {
isLinkedCase: isLinked,