167 lines
6.3 KiB
JavaScript
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();
|
|
const WORDKEY = process.env.HASHKEY;
|
|
/**
|
|
* 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 };
|
|
}
|