Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions client/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1518,16 +1518,14 @@ class API {

async bulkDownloadFiles(
projectID: string,
fileIDs: string[],
emailToNotify: string
fileIDs: string[]
) {
const arrQuery = fileIDs.map((id) => `fileID=${id}`).join(`&`);
const res = await axios.get<{ file?: string } & ConductorBaseResponse>(
`/project/${projectID}/files/bulk`,
{
params: {
fileIDs: arrQuery,
emailToNotify,
},
}
);
Expand Down
56 changes: 32 additions & 24 deletions client/src/components/FilesManager/FilesManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ interface FilesManagerProps extends SegmentProps {
projectID: string;
toggleFilesManager: () => void;
canViewDetails: boolean;
allowBulkDownload?: boolean;
projectHasDefaultLicense?: boolean;
projectVisibility?: string;
}
Expand All @@ -66,6 +67,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
projectID,
toggleFilesManager,
canViewDetails = false,
allowBulkDownload = false,
projectHasDefaultLicense = false,
projectVisibility = "private",
}) => {
Expand Down Expand Up @@ -438,7 +440,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
async function handleBulkDownload(ids: string[]) {
try {
setDownloadLoading(true);
const res = await api.bulkDownloadFiles(projectID, ids, user.email);
const res = await api.bulkDownloadFiles(projectID, ids);

if (!res.data || res.data.err) {
throw new Error("Unable to download files. Please try again later.");
Expand Down Expand Up @@ -705,12 +707,14 @@ const FilesManager: React.FC<FilesManagerProps> = ({
</Message>
)}
<Segment.Group size="large" raised className="mb-4">
{canViewDetails && (
{(canViewDetails || allowBulkDownload) && (
<Segment>
<p style={{ fontSize: "0.9em" }} className="mb-4">
If your project has supporting files, use this tool to upload and
organize them.
</p>
{canViewDetails && (
<p style={{ fontSize: "0.9em" }} className="mb-4">
If your project has supporting files, use this tool to upload and
organize them.
</p>
)}
<Button.Group
fluid
widths="7"
Expand All @@ -722,18 +726,22 @@ const FilesManager: React.FC<FilesManagerProps> = ({
: ""
}
>
<Button color="green" onClick={() => setShowUploader(true)}>
<Icon name="upload" />
Upload
</Button>
<Button
color="green"
className="!bg-green-600"
onClick={() => setShowAddFolder(true)}
>
<Icon name="add" />
New Folder
</Button>
{canViewDetails && (
<>
<Button color="green" onClick={() => setShowUploader(true)}>
<Icon name="upload" />
Upload
</Button>
<Button
color="green"
className="!bg-green-600"
onClick={() => setShowAddFolder(true)}
>
<Icon name="add" />
New Folder
</Button>
</>
)}
{itemsChecked > 1 && (
<Button
color="blue"
Expand All @@ -754,7 +762,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
)}
</Button>
)}
{itemsChecked > 1 && (
{canViewDetails && itemsChecked > 1 && (
<Button
color="teal"
disabled={itemsChecked < 1}
Expand All @@ -766,7 +774,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
Move
</Button>
)}
{itemsChecked > 0 && (
{canViewDetails && itemsChecked > 0 && (
<Button
color="yellow"
disabled={itemsChecked < 1}
Expand All @@ -780,7 +788,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
Change Access
</Button>
)}
{canBulkTag && (
{canViewDetails && canBulkTag && (
<Button
color="purple"
disabled={itemsChecked < 1}
Expand All @@ -792,7 +800,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
Bulk Tag
</Button>
)}
{itemsChecked > 1 && (
{canViewDetails && itemsChecked > 1 && (
<Button
color="red"
disabled={itemsChecked < 1}
Expand All @@ -819,7 +827,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
<Table basic attached="bottom">
<Table.Header>
<Table.Row>
{canViewDetails && (
{(canViewDetails || allowBulkDownload) && (
<Table.HeaderCell key="check" collapsing={true}>
<input
type="checkbox"
Expand Down Expand Up @@ -864,7 +872,7 @@ const FilesManager: React.FC<FilesManagerProps> = ({
if (!isTailwindLg) return MobileTableRow(item);
return (
<Table.Row className="h-[60px]" key={item.fileID}>
{canViewDetails && (
{(canViewDetails || allowBulkDownload) && (
<Table.Cell>
<input
type="checkbox"
Expand Down
1 change: 1 addition & 0 deletions client/src/screens/commons/Project/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ const CommonsProject = () => {
<FilesManager
projectID={projectID}
canViewDetails={false}
allowBulkDownload={true}
toggleFilesManager={() => setShowAssets(!showAssets)}
projectVisibility="public"
/>
Expand Down
4 changes: 2 additions & 2 deletions server/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2127,8 +2127,8 @@ router
router
.route("/project/:projectID/files/bulk")
.get(
authAPI.verifyRequest,
authAPI.getUserAttributes,
authAPI.optionalVerifyRequest,
authAPI.optionalGetUserAttributes,
middleware.validateZod(
ProjectFileValidators.bulkDownloadProjectFilesSchema
),
Expand Down
76 changes: 33 additions & 43 deletions server/api/projectfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Organization from "../models/organization.js";
import {
PROJECT_FILES_S3_CLIENT_CONFIG,
computeStructureAccessSettings,
createZIPAndNotify,
downloadProjectFiles,
getFolderContents,
getProjectFiles,
Expand Down Expand Up @@ -575,9 +574,9 @@ async function bulkDownloadProjectFiles(
res: Response
) {
try {
// 50mb limit
const MAX_COMBINED_SIZE = 52428800;
const { emailToNotify } = req.query;
// 150mb limit
const MAX_COMBINED_SIZE = 157286400; // 150 * 1024 * 1024

// @ts-ignore
const rawIds = req.query.fileIDs as string;
const projectID = req.params.projectID;
Expand Down Expand Up @@ -618,52 +617,43 @@ async function bulkDownloadProjectFiles(
foundFiles.forEach((file) => {
totalSize += file.size;
});
const isOverLimit = totalSize > MAX_COMBINED_SIZE;

if (!isOverLimit) {
// create zip file
foundFiles.forEach(async (file) => {
const fileKey = assembleUrl([projectID, file.fileID]);
downloadCommands.push(
new GetObjectCommand({
Bucket: process.env.AWS_PROJECTFILES_BUCKET,
Key: fileKey,
})
);

// If over limit, return error instead of email notification
if (totalSize > MAX_COMBINED_SIZE) {
return res.status(400).send({
err: true,
errMsg: "Too many files were requested. Please select fewer files.",
});
}

const downloadRes = await Promise.all(
downloadCommands.map((command) => storageClient.send(command))
// create zip file
foundFiles.forEach(async (file) => {
const fileKey = assembleUrl([projectID, file.fileID]);
downloadCommands.push(
new GetObjectCommand({
Bucket: process.env.AWS_PROJECTFILES_BUCKET,
Key: fileKey,
})
);
});

const zipBuff = await parseAndZipS3Objects(downloadRes, foundFiles);
if (!zipBuff) {
throw new Error("ziperror");
}

//TODO: update download count
const base64File = zipBuff.toString("base64");
const downloadRes = await Promise.all(
downloadCommands.map((command) => storageClient.send(command))
);

return res.send({
err: false,
msg: "Successfully requested download!",
file: base64File,
});
} else {
const fileKeys: string[] = [];
foundFiles.forEach((file) => {
const fileKey = assembleUrl([projectID, file.fileID]);
fileKeys.push(fileKey);
});
const zipBuff = await parseAndZipS3Objects(downloadRes, foundFiles);
if (!zipBuff) {
throw new Error("ziperror");
}

createZIPAndNotify(fileKeys, foundFiles, emailToNotify); // Don't await, just run in background and return success
//TODO: update download count
const base64File = zipBuff.toString("base64");

res.setHeader("content-type", "application/json");
return res.send({
err: false,
msg: "Successfully requested download!",
});
}
return res.send({
err: false,
msg: "Successfully requested download!",
file: base64File,
});
} catch (e) {
debugError(e);
return res.status(500).send({
Expand Down
1 change: 0 additions & 1 deletion server/api/validators/projectfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ export const bulkDownloadProjectFilesSchema = z.object({
}),
query: z.object({
fileIDs: z.string().max(2200), // allow for approx 50 file IDs in format 'fileID=123&fileID=456&fileID=789', will be parsed by the handling function
emailToNotify: z.string().email(),
}),
});

Expand Down