From 06599c844a7f5da487155dc1a5702644c03b30bf Mon Sep 17 00:00:00 2001 From: RKWojs Date: Tue, 16 Sep 2025 11:27:25 +0200 Subject: [PATCH] feat: Implement file upload structure and API for file retrieval --- docker-compose.prod.yml | 1 + docker-entrypoint-dev.sh | 8 +++++ docker-entrypoint.sh | 8 +++++ src/app/api/files/[fileId]/route.js | 50 +++++++++++++++++++++++++++ src/components/FileAttachmentsList.js | 2 +- uploads/README.md | 8 +++++ uploads/contracts/.gitkeep | 0 uploads/projects/.gitkeep | 0 uploads/tasks/.gitkeep | 0 9 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 uploads/README.md create mode 100644 uploads/contracts/.gitkeep create mode 100644 uploads/projects/.gitkeep create mode 100644 uploads/tasks/.gitkeep diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 0ceac27..ed535cc 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -13,6 +13,7 @@ services: - "3001:3000" volumes: - ./data:/app/data + - ./uploads:/app/public/uploads environment: - NODE_ENV=production - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-your-secret-key-generate-a-strong-random-string-at-least-32-characters} diff --git a/docker-entrypoint-dev.sh b/docker-entrypoint-dev.sh index 27272f0..1b46caa 100644 --- a/docker-entrypoint-dev.sh +++ b/docker-entrypoint-dev.sh @@ -8,6 +8,14 @@ echo "🚀 Starting development environment..." # Ensure data directory exists mkdir -p /app/data +# Ensure uploads directory structure exists +mkdir -p /app/public/uploads/contracts +mkdir -p /app/public/uploads/projects +mkdir -p /app/public/uploads/tasks + +# Set proper permissions for uploads directory +chmod -R 755 /app/public/uploads + # Create admin account if it doesn't exist echo "🔧 Setting up admin account..." node scripts/create-admin.js diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index b4392e4..4670af0 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -8,6 +8,14 @@ echo "🚀 Starting application..." # Ensure data directory exists mkdir -p /app/data +# Ensure uploads directory structure exists +mkdir -p /app/public/uploads/contracts +mkdir -p /app/public/uploads/projects +mkdir -p /app/public/uploads/tasks + +# Set proper permissions for uploads directory +chmod -R 755 /app/public/uploads + # Create admin account if it doesn't exist echo "🔧 Setting up admin account..." node scripts/create-admin.js diff --git a/src/app/api/files/[fileId]/route.js b/src/app/api/files/[fileId]/route.js index f5ebbea..3ed3e6c 100644 --- a/src/app/api/files/[fileId]/route.js +++ b/src/app/api/files/[fileId]/route.js @@ -1,8 +1,58 @@ import { NextResponse } from "next/server"; +import { readFile } from "fs/promises"; +import { existsSync } from "fs"; import { unlink } from "fs/promises"; import path from "path"; import db from "@/lib/db"; +export async function GET(request, { params }) { + try { + const fileId = params.fileId; + + // Get file info from database + const file = db.prepare(` + SELECT * FROM file_attachments WHERE file_id = ? + `).get(parseInt(fileId)); + + if (!file) { + return NextResponse.json( + { error: "File not found" }, + { status: 404 } + ); + } + + // Construct the full file path + const fullPath = path.join(process.cwd(), "public", file.file_path); + + // Check if file exists + if (!existsSync(fullPath)) { + return NextResponse.json( + { error: "File not found on disk" }, + { status: 404 } + ); + } + + // Read the file + const fileBuffer = await readFile(fullPath); + + // Return the file with appropriate headers + return new NextResponse(fileBuffer, { + headers: { + "Content-Type": file.mime_type || "application/octet-stream", + "Content-Disposition": `attachment; filename="${encodeURIComponent(file.original_filename)}"`, + "Content-Length": fileBuffer.length.toString(), + }, + }); + + } catch (error) { + console.error("Error downloading file:", error); + return NextResponse.json( + { error: "Failed to download file" }, + { status: 500 } + ); + } +} + export async function DELETE(request, { params }) { try { const fileId = params.fileId; diff --git a/src/components/FileAttachmentsList.js b/src/components/FileAttachmentsList.js index eaf5177..a276bcc 100644 --- a/src/components/FileAttachmentsList.js +++ b/src/components/FileAttachmentsList.js @@ -149,7 +149,7 @@ export default function FileAttachmentsList({ entityType, entityId, onFilesChang