partial synch with ph2 updates
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
// pages/admin/storage.js
|
||||
import { useState } from "react";
|
||||
import Head from "next/head";
|
||||
import CookieBanner from "../../components/cookieBanner";
|
||||
import Header from "../../components/header";
|
||||
import Footer from "../../components/footer";
|
||||
import { connect } from "react-redux";
|
||||
import { wrapper } from "../../store/store";
|
||||
|
||||
import StorageTab from "../../components/admin/tabs/storage";
|
||||
import AccountsTab from "../../components/admin/tabs/accounts";
|
||||
import AppealsTab from "../../components/admin/tabs/appeals";
|
||||
import DocumentsTab from "../../components/admin/tabs/documents";
|
||||
|
||||
import { fetchAdminStorageData } from "../../components/admin/utils/serverside";
|
||||
import { getNewAppeals } from "../../actions";
|
||||
|
||||
import { getSearchDetails } from "../../components/utils";
|
||||
|
||||
import {
|
||||
setSearchDetails,
|
||||
setSearchResults,
|
||||
} from "../../store/searchOutput/action";
|
||||
import { setCurrentPage } from "../../store/currentView/action";
|
||||
|
||||
const StoragePage = (props) => {
|
||||
const {
|
||||
data,
|
||||
userData,
|
||||
repCompleteCount,
|
||||
searchResultsObj,
|
||||
docsOffline,
|
||||
showFilteredDocs,
|
||||
} = props;
|
||||
const [whichTab, setWhichTab] = useState("documents");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>Admin Browser</title>
|
||||
</Head>
|
||||
<div id="page_wrapper">
|
||||
<CookieBanner />
|
||||
<Header />
|
||||
|
||||
<div
|
||||
className="govuk-width-containera"
|
||||
style={{ width: "90%", margin: "auto" }}
|
||||
>
|
||||
<div className="js-enabled govuk-template__body govuk-frontend-supported">
|
||||
<div className="govuk-tabs" data-module="govuk-tabs">
|
||||
<h2 className="govuk-tabs__title">Contents</h2>
|
||||
|
||||
{/* Tabs */}
|
||||
<ul className="govuk-tabs__list">
|
||||
{[
|
||||
"documents",
|
||||
"appeals",
|
||||
"storage",
|
||||
"accounts",
|
||||
].map((tab) => (
|
||||
<li
|
||||
key={tab}
|
||||
className={
|
||||
whichTab === tab
|
||||
? "govuk-tabs__list-item govuk-tabs__list-item--selected"
|
||||
: "govuk-tabs__list-item"
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="govuk-tabs__tab"
|
||||
href={`#${tab}`}
|
||||
onClick={() => {
|
||||
setWhichTab(tab);
|
||||
tab === "appeals" &&
|
||||
props.setCurrentPage(1);
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{tab === "documents" &&
|
||||
"Latest Documents"}
|
||||
{tab === "appeals" &&
|
||||
"Latest Appeals"}
|
||||
{tab === "storage" &&
|
||||
"Storage Account"}
|
||||
{tab === "accounts" &&
|
||||
"User Accounts"}
|
||||
</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"
|
||||
? "govuk-tabs__panel"
|
||||
: "govuk-tabs__panel govuk-tabs__panel--hidden"
|
||||
}
|
||||
>
|
||||
<StorageTab
|
||||
data={data}
|
||||
repCompleteCount={repCompleteCount}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
whichTab === "accounts"
|
||||
? "govuk-tabs__panel"
|
||||
: "govuk-tabs__panel govuk-tabs__panel--hidden"
|
||||
}
|
||||
>
|
||||
<AccountsTab userData={userData} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps = wrapper.getServerSideProps(
|
||||
(store) => async (ctx) => {
|
||||
const { query, req, res } = ctx;
|
||||
// IP restriction check
|
||||
const ALLOWED_IPS = process.env.ALLOWED_IPS
|
||||
? process.env.ALLOWED_IPS.split(",").map((ip) => ip.trim())
|
||||
: [];
|
||||
const LOCALHOST_IPS = ["127.0.0.1", "::1"];
|
||||
const forwarded = req.headers["x-forwarded-for"];
|
||||
const ip =
|
||||
typeof forwarded === "string"
|
||||
? forwarded.split(",")[0]
|
||||
: req.socket.remoteAddress;
|
||||
|
||||
if (![...ALLOWED_IPS, ...LOCALHOST_IPS].includes(ip)) {
|
||||
return {
|
||||
redirect: { destination: "/403", permanent: false },
|
||||
};
|
||||
}
|
||||
|
||||
// 🔹 fetch actual data
|
||||
const { data, userData, repCompleteCount } =
|
||||
await fetchAdminStorageData();
|
||||
|
||||
const newAppeals = await getNewAppeals();
|
||||
|
||||
const searchDetailsObj = await getSearchDetails(newAppeals);
|
||||
|
||||
store.dispatch(setSearchResults(newAppeals));
|
||||
store.dispatch(setSearchDetails(searchDetailsObj));
|
||||
const state = store.getState();
|
||||
|
||||
store.dispatch(setCurrentPage(1));
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
userData,
|
||||
repCompleteCount,
|
||||
docsOffline: process.env.DOCAPI_OFFLINE || false,
|
||||
showFilteredDocs: process.env.SHOWFILTERDOCS || false,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
console.log("===============================\n state:", state);
|
||||
return {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(StoragePage);
|
||||
@@ -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: {
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @swagger
|
||||
* /api/endpoint/getbasicsearch_api:
|
||||
* get:
|
||||
* tags: [Search]
|
||||
* description: Basic search
|
||||
* parameters:
|
||||
* - name: searchString
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Success
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
azureHeadersPagedCustom,
|
||||
consoleLogger,
|
||||
getToken,
|
||||
} from "../../../actions";
|
||||
import { number } from "prop-types";
|
||||
|
||||
const WORDKEY = process.env.HASHKEY;
|
||||
|
||||
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 encryptDocReference = (documentRef) => {
|
||||
var hashlink = CryptoJS.HmacSHA256(
|
||||
"documents/download/" + documentRef,
|
||||
CryptoJS.enc.Hex.parse(WORDKEY)
|
||||
);
|
||||
hashlink = hashlink.toString(CryptoJS.enc.Hex);
|
||||
|
||||
var hashStr =
|
||||
"/api/documents/download/" + documentRef + "?hash=" + hashlink;
|
||||
|
||||
return hashStr;
|
||||
};
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var pageNumber = req.query.pageNumber || 1;
|
||||
var token = await getToken();
|
||||
|
||||
var orderby = req.query.orderby || "createdon";
|
||||
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) {
|
||||
const documentTypeArr = documentType.split(",");
|
||||
|
||||
docTypeQueryString = " and (";
|
||||
documentTypeArr.forEach(function (item, index) {
|
||||
console.log(item, index);
|
||||
|
||||
if (item != "all") {
|
||||
docTypeQueryString +=
|
||||
" pinswg_isharedocumentlocations eq " + item;
|
||||
|
||||
docTypeQueryString +=
|
||||
index < documentTypeArr.length - 1 ? " or " : "";
|
||||
}
|
||||
});
|
||||
docTypeQueryString += " )";
|
||||
} else {
|
||||
docTypeQueryString +=
|
||||
" and pinswg_isharedocumentlocations eq " + documentType;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
resultDate.setUTCDate(today.getUTCDate() - days); // subtract weeks
|
||||
resultDate.setUTCHours(0, 0, 0, 0); // reset time to 00:00:00
|
||||
return resultDate.toISOString().replace(/\.000Z$/, "Z"); // format as 'YYYY-MM-DDT00:00:00Z'
|
||||
}
|
||||
|
||||
var queryUrl =
|
||||
"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 +
|
||||
" " +
|
||||
fieldSort +
|
||||
"&$count=true" +
|
||||
"&$expand=pinswg_DocumentIds($select = ticketnumber,pinswg_publishtoweb)" +
|
||||
(typeof pageNumber != "undefined"
|
||||
? "&$skiptoken=" + '<cookie pagenumber="' + pageNumber + '" />'
|
||||
: "");
|
||||
|
||||
console.log(
|
||||
"\n==========================================\n",
|
||||
"\nnew docs search---- ",
|
||||
"\n\nQuery url: " + queryUrl,
|
||||
"\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
"\n==========================================\n"
|
||||
);
|
||||
|
||||
var apiResponse = axios
|
||||
.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPagedCustom(token.access_token, showNumberOfRecords)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
let flattened = data.value.map((r) => ({
|
||||
...r,
|
||||
ticketnumber: r.pinswg_DocumentIds?.ticketnumber || null,
|
||||
publishtoweb: r.pinswg_DocumentIds?.pinswg_publishtoweb || null,
|
||||
}));
|
||||
|
||||
data.value = flattened;
|
||||
data.value.forEach(function (element) {
|
||||
element.pinswg_hashlink = encryptDocReference(
|
||||
element.pinswg_isharedocumentreference
|
||||
);
|
||||
});
|
||||
|
||||
var dataStr;
|
||||
|
||||
_.has(data, "@odata.nextLink") == true &&
|
||||
((dataStr = JSON.stringify(data["@odata.nextLink"])),
|
||||
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
});
|
||||
|
||||
return apiResponse;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @swagger
|
||||
* /api/endpoint/getbasicsearch_api:
|
||||
* get:
|
||||
* tags: [Search]
|
||||
* description: Basic search
|
||||
* parameters:
|
||||
* - name: searchString
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Success
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
azureHeadersPagedCustom,
|
||||
consoleLogger,
|
||||
getToken,
|
||||
} from "../../../actions";
|
||||
|
||||
const WORDKEY = process.env.HASHKEY;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var searchString = req.query.searchString;
|
||||
var pageNumber = req.query.pageNumber || 1;
|
||||
var token = await getToken();
|
||||
|
||||
var orderby = req.query.orderby || "createdon";
|
||||
var fieldSort = req.query.fieldSort || "desc";
|
||||
var showNumberOfRecords = req.query.showNumberOfRecords || 10;
|
||||
|
||||
var queryUrl =
|
||||
"incidents?$select=caseorigincode,pinswg_publishtoweb,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$orderby=" +
|
||||
orderby +
|
||||
" " +
|
||||
fieldSort +
|
||||
"&$count=true" +
|
||||
(typeof pageNumber != "undefined"
|
||||
? "&$skiptoken=" + '<cookie pagenumber="' + pageNumber + '" />'
|
||||
: "");
|
||||
|
||||
console.log(
|
||||
"\n==========================================\n",
|
||||
"\nnew appeal search ",
|
||||
"\n\nQuery url: " + queryUrl,
|
||||
"\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
"\n==========================================\n"
|
||||
);
|
||||
|
||||
var apiResponse = axios
|
||||
.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPagedCustom(token.access_token, showNumberOfRecords)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
var dataStr;
|
||||
_.has(data, "@odata.nextLink") == true &&
|
||||
((dataStr = JSON.stringify(data["@odata.nextLink"])),
|
||||
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
});
|
||||
|
||||
return apiResponse;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -306,7 +306,7 @@ export default async function ApiProxy(req, res) {
|
||||
"MetadataId": "8d31911b-b8ea-ef11-ab08-00224800be9c",
|
||||
"appealTypeID": "846040002",
|
||||
"tmpNav": "pinswg_sipsid",
|
||||
"NavigationProperty": "pinswg_SIPSids",
|
||||
"NavigationProperty": "pinswg_sipscase",
|
||||
"value": "SIP",
|
||||
},
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import { azureHeadersPaged, consoleLogger, getToken } from "../../../actions";
|
||||
import { getSelectQuery } from "../../../actions/selectQueryTypes";
|
||||
|
||||
import { getNavigationPropertyByPrimaryAttribute } from "../../../components/utils";
|
||||
const WORDKEY = process.env.HASHKEY;
|
||||
|
||||
const WEBAPI_URL =
|
||||
@@ -59,15 +59,27 @@ export default async function ApiProxy(req, res) {
|
||||
var incidentID = req.query.incidentID;
|
||||
var token = await getToken();
|
||||
|
||||
let navigationProperty =
|
||||
getNavigationPropertyByPrimaryAttribute(
|
||||
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";
|
||||
"&$count=true" +
|
||||
"&$expand=" +
|
||||
navigationProperty +
|
||||
"($select=ticketnumber)";
|
||||
|
||||
//" and statuscode eq 1&$count=true";
|
||||
|
||||
queryUrl =
|
||||
@@ -86,10 +98,18 @@ export default async function ApiProxy(req, res) {
|
||||
azureHeadersPaged(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
let flattened = data.value.map((r) => ({
|
||||
...r,
|
||||
ticketnumber: r[navigationProperty]?.ticketnumber || null,
|
||||
}));
|
||||
|
||||
data.value = flattened;
|
||||
|
||||
var dataStr;
|
||||
_.has(data, "@odata.nextLink") == true &&
|
||||
((dataStr = JSON.stringify(data["@odata.nextLink"])),
|
||||
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
|
||||
|
||||
return res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@@ -207,6 +207,35 @@ const SignIn = (props) => {
|
||||
};
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const { query, req, res } = context;
|
||||
|
||||
// Load allowed IPs from env and trim spaces
|
||||
const ALLOWED_IPS = process.env.ALLOWED_IPS
|
||||
? process.env.ALLOWED_IPS.split(",").map((ip) => ip.trim())
|
||||
: [];
|
||||
|
||||
// Always allow localhost addresses
|
||||
const LOCALHOST_IPS = ["127.0.0.1", "::1"];
|
||||
|
||||
// Get IP address from headers or socket
|
||||
const forwarded = req.headers["x-forwarded-for"];
|
||||
const ip =
|
||||
typeof forwarded === "string"
|
||||
? forwarded.split(",")[0]
|
||||
: req.socket.remoteAddress;
|
||||
|
||||
console.log("Visitor IP:", ip);
|
||||
|
||||
// Check whitelist + localhost
|
||||
if (![...ALLOWED_IPS, ...LOCALHOST_IPS].includes(ip)) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/403", // custom "Access Denied" page
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.SHOWLOGIN == false) {
|
||||
return {
|
||||
redirect: {
|
||||
|
||||
@@ -81,9 +81,16 @@ const CaseHome = (props) => {
|
||||
props.awaitingSubmission.awaitingSubmission
|
||||
}
|
||||
caseReference={
|
||||
props.searchResultsObj.searchResultsObj.value[0]
|
||||
.caseReference
|
||||
}
|
||||
ticketnumber={
|
||||
props.searchResultsObj.searchResultsObj.value[0]
|
||||
.ticketnumber
|
||||
}
|
||||
// ticketnumber={
|
||||
// props.currentView.caseReference.ticketnumber
|
||||
// }
|
||||
currentType={props.currentType}
|
||||
appealTypeID={
|
||||
props.searchResultsObj.searchResultsObj.value[0]
|
||||
|
||||
+37
-29
@@ -20,7 +20,7 @@ import { wrapper } from "../store/store";
|
||||
import ServiceBanner from "../components/servicebanner";
|
||||
|
||||
const Home = (props) => {
|
||||
const { footerLinks, pages, showMap } = props;
|
||||
const { footerLinks, pages, showMap, showLoginCheck } = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
@@ -105,6 +105,7 @@ const Home = (props) => {
|
||||
showMap={showMap}
|
||||
searchString="DNS"
|
||||
searchResultsObj={props.searchResultsObj}
|
||||
showLoginCheck={showLoginCheck}
|
||||
/>
|
||||
</div>
|
||||
<Footer footerLinks={footerLinks} ticketnumber={props} />
|
||||
@@ -123,40 +124,47 @@ 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: { showMap: showMapCheck },
|
||||
props: {
|
||||
showMap: showMapCheck,
|
||||
showLoginCheck: showLoginCheck,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
@@ -70,7 +70,9 @@ const CaseHome = (props) => {
|
||||
<Head>
|
||||
<title>
|
||||
Reference:{" "}
|
||||
{props.currentView.caseReference.currentReference}{" "}
|
||||
{props.currentView.caseReference.currentReference ||
|
||||
props.searchResultsObj.searchResultsObj.value[0]
|
||||
.title}{" "}
|
||||
</title>
|
||||
</Head>
|
||||
<div id="page_wrapper">
|
||||
@@ -104,18 +106,17 @@ 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
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -220,10 +221,10 @@ export const getServerSideProps = wrapper.getServerSideProps(
|
||||
|
||||
store.dispatch(setSearch(developmentQuery));
|
||||
|
||||
console.log(
|
||||
searchResultsObj["@odata.count"] > 1 ||
|
||||
searchResultsObj["@odata.count"] < 1
|
||||
);
|
||||
// console.log(
|
||||
// searchResultsObj["@odata.count"] > 1 ||
|
||||
// searchResultsObj["@odata.count"] < 1
|
||||
// );
|
||||
|
||||
if (searchResultsObj["@odata.count"] < 1) {
|
||||
return {
|
||||
@@ -440,6 +441,7 @@ const getDetails = (resultsObj, detailsType) => {
|
||||
];
|
||||
break;
|
||||
case "awaitingSubmission":
|
||||
case "myWatchedCases":
|
||||
case "myRepresentations":
|
||||
caseID = data.ticketnumber;
|
||||
break;
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user