storage admin update

This commit is contained in:
2025-08-14 08:25:20 +01:00
parent 8e9d89a2af
commit b86712efb8
3 changed files with 416 additions and 293 deletions
-27
View File
@@ -1715,33 +1715,6 @@ function formatDateDisplay(date) {
: "Unknown"; : "Unknown";
} }
function formatBlobDates(blob) {
const created = blob.createdOn ? new Date(blob.createdOn) : null;
const modified = blob.lastModified ? new Date(blob.lastModified) : null;
if (!created && !modified) return "Unknown";
// If both exist and are the same
if (created && modified && created.getTime() === modified.getTime()) {
return `${created.toLocaleString("en-GB")} (${formatTimeSince(
created
)})`;
}
// If modified exists and is newer than created
if (created && modified && modified.getTime() > created.getTime()) {
return `Created: ${created.toLocaleString("en-GB")} (${formatTimeSince(
created
)}), Modified: ${modified.toLocaleString("en-GB")} (${formatTimeSince(
modified
)})`;
}
// Only one date exists
const date = modified || created;
return `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})`;
}
export async function listBlobHierarchicalForUser(containerClient) { export async function listBlobHierarchicalForUser(containerClient) {
const blobNames = []; const blobNames = [];
for await (const blob of containerClient.listBlobsFlat()) { for await (const blob of containerClient.listBlobsFlat()) {
+29
View File
@@ -207,6 +207,35 @@ const SignIn = (props) => {
}; };
export async function getServerSideProps(context) { 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) { if (process.env.SHOWLOGIN == false) {
return { return {
redirect: { redirect: {
+135 -14
View File
@@ -110,11 +110,11 @@ const deleteCaseItem = (containerID, caseID) => {
}); });
}; };
export default function StoragePage({ data }) { export default function StoragePage(props) {
console.log(data); const { data, userData } = props;
const [showRepJson, setShowRepJson] = useState(true); const [showRepJson, setShowRepJson] = useState(true);
const [showTmpFile, setShowTmpFile] = useState(true); const [showTmpFile, setShowTmpFile] = useState(true);
const [whichTab, setWhichTab] = useState("storage");
const toggleAll = () => { const toggleAll = () => {
const newState = !(showRepJson || showTmpFile); const newState = !(showRepJson || showTmpFile);
@@ -130,20 +130,68 @@ export default function StoragePage({ data }) {
<CookieBanner /> <CookieBanner />
<Header /> <Header />
<div className="govuk-width-container"> <div className="govuk-width-container">
<div className="govuk-main-wrapper govuk-main-wrapper--auto-spacing"> <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>
<ul className="govuk-tabs__list">
<li
className={
whichTab == "storage"
? "govuk-tabs__list-item govuk-tabs__list-item--selected"
: "govuk-tabs__list-item "
}
>
<a
className="govuk-tabs__tab"
href="#storage"
onClick={() => setWhichTab("storage")}
>
Storage Account
</a>
</li>
<li
className={
whichTab == "accounts"
? "govuk-tabs__list-item govuk-tabs__list-item--selected"
: "govuk-tabs__list-item "
}
>
<a
className="govuk-tabs__tab"
href="#accounts"
onClick={() => setWhichTab("accounts")}
>
User Accounts
</a>
</li>
</ul>
<div
className={
whichTab == "storage"
? "govuk-tabs__panel "
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
id="storage"
>
<h1>Storage Account Contents</h1> <h1>Storage Account Contents</h1>
{/* Toggle buttons */} {/* Toggle buttons */}
<div style={{ marginBottom: "0.2rem" }}> <div style={{ marginBottom: "0.2rem" }}>
<button <button
className="govuk-button govuk-button--secondary" className="govuk-button govuk-button--secondary"
onClick={() => setShowRepJson(!showRepJson)} onClick={() =>
setShowRepJson(!showRepJson)
}
> >
{showRepJson ? "Hide Reps" : "Show Reps"} {showRepJson
? "Hide Reps"
: "Show Reps"}
</button> </button>
<button <button
className="govuk-button govuk-button--secondary" className="govuk-button govuk-button--secondary"
onClick={() => setShowTmpFile(!showTmpFile)} onClick={() =>
setShowTmpFile(!showTmpFile)
}
style={{ marginLeft: "0.5rem" }} style={{ marginLeft: "0.5rem" }}
> >
{showTmpFile {showTmpFile
@@ -160,16 +208,32 @@ export default function StoragePage({ data }) {
</div> </div>
{data.map((user) => ( {data.map((user) => (
<div key={user.id} className="govuk-grid-row"> <div
key={user.id}
className="govuk-grid-row"
>
{user.containers.map((c) => ( {user.containers.map((c) => (
<div key={c.container} className="card"> <div
key={c.container}
className="card"
>
<div className="card-body"> <div className="card-body">
<h3> <h3>
{c.container} - {user.email} {c.container} -{" "}
<Link
href={
"/auth/signin2?email=" +
user.email
}
>
{user.email}
</Link>
</h3> </h3>
{c.folders.map((folder) => ( {c.folders.map((folder) => (
<div <div
key={folder.folderPath} key={
folder.folderPath
}
style={ style={
showRepJson && showRepJson &&
folder.hasRepJson folder.hasRepJson
@@ -224,7 +288,8 @@ export default function StoragePage({ data }) {
window.location.reload()); window.location.reload());
}} }}
> >
Delete this TMP Delete
this TMP
appeal appeal
</button> </button>
</> </>
@@ -260,7 +325,8 @@ export default function StoragePage({ data }) {
window.location.reload()); window.location.reload());
}} }}
> >
Delete Rep Delete
Rep
</button> </button>
{folder.repComplete && ( {folder.repComplete && (
<button <button
@@ -384,6 +450,7 @@ export default function StoragePage({ data }) {
blob.contentLength || blob.contentLength ||
blob.size blob.size
)} )}
) )
</Link>{" "} </Link>{" "}
{blob.lastModified && ( {blob.lastModified && (
@@ -408,6 +475,50 @@ export default function StoragePage({ data }) {
</div> </div>
))} ))}
</div> </div>
<div
className={
whichTab == "accounts"
? "govuk-tabs__panel "
: "govuk-tabs__panel govuk-tabs__panel--hidden"
}
id="accounts"
>
<h1>User Accounts </h1>
<dl className=" govuk-summary-list govuk-!-margin-bottom-9 results">
<div class="govuk-summary-list__row results-headings">
<dd className="govuk-summary-list__key govuk-!-font-size-16 ">
Name
</dd>
<dd className="govuk-summary-list__key govuk-!-font-size-16">
Last accessed
</dd>
</div>
{userData.map((user) => (
<div
key={user.id}
className=" govuk-summary-list__row"
>
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
<Link
target="_blank"
href={
"/auth/signin2?email=" +
user.email
}
>
{user.email}
</Link>
</dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
Last accessed: {user.created}{" "}
</dd>
</div>
))}
</dl>
</div>
</div>
</div>
</div> </div>
<Footer /> <Footer />
</div> </div>
@@ -587,5 +698,15 @@ export async function getServerSideProps({ req }) {
}) })
); );
return { props: { data: data.filter(Boolean) } }; let userData = await Promise.all(
users
.filter((user) => user.email && user.email.trim() !== "")
.map(async (user) => ({
id: user.id,
email: user.email,
created: user.emailVerified?.toLocaleString("en-GB") || "",
}))
);
return { props: { data: data.filter(Boolean), userData: userData } };
} }