diff --git a/backend/index.js b/backend/index.js index e9d5aee..90708c3 100644 --- a/backend/index.js +++ b/backend/index.js @@ -64,8 +64,10 @@ app.use("/steps", stepsDeleteRoute); // "/attachments" const attachmentsNewRoute = require("./routes/attachments/new")(sequelize); const attachmentsDeleteRoute = require("./routes/attachments/delete")(sequelize); +const attachmentsDownloadRoute = require("./routes/attachments/download")(sequelize); app.use("/attachments", attachmentsNewRoute); app.use("/attachments", attachmentsDeleteRoute); +app.use("/attachments", attachmentsDownloadRoute); // "/runs" const runsIndexRoute = require("./routes/runs/index")(sequelize); diff --git a/backend/routes/attachments/download.js b/backend/routes/attachments/download.js new file mode 100644 index 0000000..e526cd3 --- /dev/null +++ b/backend/routes/attachments/download.js @@ -0,0 +1,34 @@ +const express = require("express"); +const router = express.Router(); +const path = require("path"); +const fs = require("fs"); +const defineAttachment = require("../../models/attachments"); +const { DataTypes } = require("sequelize"); + +module.exports = function (sequelize) { + const Attachment = defineAttachment(sequelize, DataTypes); + router.get("/download/:attachmentId", async (req, res) => { + const attachmentId = req.params.attachmentId; + + try { + const attachment = await Attachment.findByPk(attachmentId); + if (!attachment) { + return res.status(404).send("Attachment not found"); + } + + const filename = attachment.path.split("/").pop(); + const filePath = path.join(__dirname, `../../public/uploads/${filename}`); + + if (!fs.existsSync(filePath)) { + return res.status(404).json({ error: "File not found" }); + } + + res.download(filePath); + } catch (error) { + console.error(error); + res.status(500).send("Internal Server Error"); + } + }); + + return router; +}; diff --git a/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-attachments-editor.tsx b/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-attachments-editor.tsx index 13d7d55..db881a2 100644 --- a/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-attachments-editor.tsx +++ b/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-attachments-editor.tsx @@ -4,11 +4,16 @@ import { Trash, ArrowDownToLine } from "lucide-react"; type Props = { attachments: AttachmentType[]; + onAttachmentDownload: ( + attachmentId: number, + downloadFileName: string + ) => void; onAttachmentDelete: (attachmentId: number) => void; }; export default function CaseAttachmentsEditor({ attachments = [], + onAttachmentDownload, onAttachmentDelete, }: Props) { let images = []; @@ -70,7 +75,7 @@ export default function CaseAttachmentsEditor({ isIconOnly size="sm" className="bg-transparent rounded-full" - onPress={() => console.log("download")} + onPress={() => onAttachmentDownload(file.id, file.title)} > diff --git a/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-editor.tsx b/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-editor.tsx index 1313259..b74dbf7 100644 --- a/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-editor.tsx +++ b/frontend/app/projects/[projectId]/folders/[folderId]/cases/[caseId]/case-editor.tsx @@ -22,6 +22,7 @@ import { fetchDeleteStep, updateCase, fetchCreateAttachments, + fetchDownloadAttachment, fetchDeleteAttachment, } from "./caseControl"; @@ -370,6 +371,9 @@ export default function CaseEditor({
Attachments
+ fetchDownloadAttachment(attachmentId, downloadFileName) + } onAttachmentDelete={onAttachmentDelete} />