Files
pedwfrontend/components/admin/utils/serverside.js
T

167 lines
6.3 KiB
JavaScript

// components/admin/utils/serverStorage.js
import { DefaultAzureCredential } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";
import { PrismaClient } from "@prisma/client";
import CryptoJS from "crypto-js";
import { getUpToLastSlash, streamToString } from "../utils/adminHelper";
import { listContainersForUser } from "../../../actions/azurestorage";
const prisma = global.prisma || new PrismaClient();
/**
* Generate HMAC hash for blob API link.
*/
function hashAPIPath(queryPath, WORDKEY) {
let hashlink = CryptoJS.HmacSHA256(
queryPath,
CryptoJS.enc.Hex.parse(WORDKEY)
);
return hashlink.toString(CryptoJS.enc.Hex);
}
/**
* Fetch blob structure + users for admin storage page.
*/
export async function fetchAdminStorageData() {
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const creds = new DefaultAzureCredential();
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
creds
);
const prisma = global.prisma || new PrismaClient();
const users = await prisma.user.findMany();
let data = await Promise.all(
users.map(async (user) => {
const containers = await listContainersForUser(
blobServiceClient,
`${user.id}`,
user.email
);
const containersWithHashes = await Promise.all(
containers.map(async (container) => {
const groupedByFolder = await container.blobs.reduce(
async (accP, blob) => {
const acc = await accP;
const folderPath =
getUpToLastSlash(blob.name.trim()) || "";
const hashedfilepath = hashAPIPath(
`/api/file/downloadblob?container=${
container.container
}&casefolderID=${folderPath}&blobname=${blob.name
.substring(blob.name.lastIndexOf("/") + 1)
.trim()}`,
process.env.HASHKEY
);
const fileNameOnly = blob.name.substring(
blob.name.lastIndexOf("/") + 1
);
const isTmpFile = fileNameOnly.startsWith("TMP-");
const blobWithHash = {
...blob,
hashedfilepath,
isTmpFile,
};
let folderGroup = acc.find(
(f) => f.folderPath === folderPath
);
if (!folderGroup) {
folderGroup = {
folderPath,
blobs: [],
hasRepJson: false,
repJsonBlob: null,
repComplete: false,
hasTmpFile: false,
};
acc.push(folderGroup);
}
folderGroup.blobs.push(blobWithHash);
if (isTmpFile) {
folderGroup.hasTmpFile = true;
}
// rep.json handling
if (blob.name.toLowerCase().endsWith("rep.json")) {
folderGroup.hasRepJson = true;
folderGroup.repJsonBlob = blobWithHash;
const containerClient =
blobServiceClient.getContainerClient(
container.container
);
const blockBlobClient =
containerClient.getBlockBlobClient(
blob.name
);
try {
const downloadResponse =
await blockBlobClient.download(0);
const downloaded = await streamToString(
downloadResponse.readableStreamBody
);
const json = JSON.parse(downloaded);
folderGroup.repComplete = Boolean(
json.repComplete
);
} catch (err) {
console.error(
"Error reading rep.json",
err
);
folderGroup.repComplete = false;
}
}
return acc;
},
Promise.resolve([])
);
return { ...container, folders: groupedByFolder };
})
);
return containersWithHashes.length > 0
? {
id: user.id,
email: user.email,
containers: containersWithHashes,
}
: null;
})
);
data = data.filter(Boolean);
let userData = users
.filter((user) => user.email && user.email.trim() !== "")
.map((user) => ({
id: user.id,
email: user.email,
created: user.emailVerified?.toLocaleString("en-GB") || "",
}));
let repCompleteCount = 0;
data.forEach((user) => {
user.containers.forEach((container) => {
container.folders.forEach((folder) => {
if (folder.repComplete === true) repCompleteCount++;
});
});
});
return { data, userData, repCompleteCount };
}