diff --git a/src/components/pages/folders/views/FolderTableView.tsx b/src/components/pages/folders/views/FolderTableView.tsx index ddc24db8..e0901286 100755 --- a/src/components/pages/folders/views/FolderTableView.tsx +++ b/src/components/pages/folders/views/FolderTableView.tsx @@ -16,6 +16,7 @@ import { IconShare, IconShareOff, IconTrashFilled, + IconZip, } from '@tabler/icons-react'; import ViewFilesModal from '../ViewFilesModal'; import EditFolderNameModal from '../EditFolderNameModal'; @@ -169,6 +170,14 @@ export default function FolderTableView() { + + window.open(`/api/user/folders/${folder.id}/export`, '_blank')} + > + + + { + server.get<{ Params: Params }>(PATH, { preHandler: [userMiddleware] }, async (req, res) => { + const { id } = req.params; + + const folder = await prisma.folder.findUnique({ + where: { + id, + }, + include: { + files: true, + }, + }); + if (!folder) return res.notFound('Folder not found'); + if (req.user.id !== folder.userId) return res.forbidden('You do not own this folder'); + + if (!folder.files.length) return res.badRequest("Can't export an empty folder."); + + logger.info(`folder export requested: ${folder.name}`, { user: req.user.id, folder: folder.id }); + + res.hijack(); + + const zip = archiver('zip', { + zlib: { level: 9 }, + }); + + zip.pipe(res.raw); + + for (const file of folder.files) { + const stream = await datasource.get(file.name); + if (!stream) { + logger.warn('failed to get file stream for folder export', { file: file.id, folder: folder.id }); + continue; + } + + zip.append(stream, { name: file.name }); + } + + zip.on('error', (err) => { + logger.error('error during folder export zip creation', { folder: folder.id }).error(err as Error); + }); + + zip.on('finish', () => { + logger.info(`folder export completed: ${folder.name}`, { user: req.user.id, folder: folder.id }); + }); + + await zip.finalize(); + }); + done(); + }, + { name: PATH }, +); diff --git a/src/server/routes/api/user/folders/[id].ts b/src/server/routes/api/user/folders/[id]/index.ts similarity index 100% rename from src/server/routes/api/user/folders/[id].ts rename to src/server/routes/api/user/folders/[id]/index.ts