import { Request, Response } from "express"; import fs from "fs-extra"; import JSZip from "jszip"; import path from "path"; import { logger } from "../server"; import ListableChecker from "../util/listableChecker"; import { PathToRoBillsFolder, PathToRoFolder } from "../util/pathGenerators"; import { BillsRelativeFilePath, JobRelativeFilePath } from "../util/serverInit"; //param: files: string[] | array of filenames. export async function jobsDownloadMedia(req: Request, res: Response) { const jobid: string = (req.body.jobid || "").trim(); try { //Do we need all files or just some files? const files: string[] = req.body.files || []; const zip: JSZip = new JSZip(); await fs.ensureDir(PathToRoFolder(jobid)); logger.debug(`Generating batch download for Job ID ${jobid}`, files); //Prepare the zip file. const jobFileList: fs.Dirent[] = ( await fs.readdir(PathToRoFolder(jobid), { withFileTypes: true }) ).filter((f) => f.isFile() && ListableChecker(f)); const billFileList: fs.Dirent[] = ( await fs.readdir(PathToRoBillsFolder(jobid), { withFileTypes: true }) ).filter((f) => f.isFile() && ListableChecker(f)); if (files.length === 0) { //Get everything. await Promise.all( jobFileList.map(async (file) => { //Do something async const fileOnDisk: Buffer = await fs.readFile(JobRelativeFilePath(jobid, file.name)); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); }) ); await Promise.all( billFileList.map(async (file) => { //Do something async const fileOnDisk: Buffer = await fs.readFile(BillsRelativeFilePath(jobid, file.name)); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); }) ); } else { //Get the files that are in the list and see which are requested. await Promise.all( jobFileList.map(async (file) => { if (files.includes(path.parse(path.basename(file.name)).base)) { // File is in the set of requested files. const fileOnDisk: Buffer = await fs.readFile(JobRelativeFilePath(jobid, file.name)); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); } }) ); await Promise.all( billFileList.map(async (file) => { if (files.includes(path.parse(path.basename(file.name)).base)) { // File is in the set of requested files. const fileOnDisk: Buffer = await fs.readFile(BillsRelativeFilePath(jobid, file.name)); zip.file(path.parse(path.basename(file.name)).base, fileOnDisk); } }) ); } //Send it as a response to download it automatically. // res.setHeader("Content-disposition", "attachment; filename=" + filename); zip .generateNodeStream({ type: "nodebuffer", streamFiles: true //encodeFileName: (filename) => `${jobid}.zip`, }) .pipe(res); } catch (error) { logger.error("Error downloading job media.", { jobid, error: (error as Error).message }); res.status(500).json((error as Error).message); } }