// app/api/rfq-download/route.ts import { NextRequest, NextResponse } from 'next/server'; import { readFile, access, constants } from 'fs/promises'; import { join } from 'path'; import db from '@/db/db'; import { rfqAttachments, vendorResponseAttachments } from '@/db/schema/rfq'; import { eq } from 'drizzle-orm'; export async function GET(request: NextRequest) { try { // 파일 경로 파라미터 받기 const path = request.nextUrl.searchParams.get("path"); if (!path) { return NextResponse.json( { error: "File path is required" }, { status: 400 } ); } // DB에서 파일 정보 조회 (정확히 일치하는 filePath로 검색) const [dbRecord] = await db .select({ fileName: vendorResponseAttachments.fileName, filePath: vendorResponseAttachments.filePath }) .from(vendorResponseAttachments) .where(eq(vendorResponseAttachments.filePath, path)); // 파일 정보 설정 let fileName; if (dbRecord) { // DB에서 찾은 경우 원본 파일명 사용 fileName = dbRecord.fileName; console.log("DB에서 원본 파일명 찾음:", fileName); } else { // DB에서 찾지 못한 경우 경로에서 파일명 추출 fileName = path.split('/').pop() || 'download'; } // 파일 경로 구성 const storedPath = path.replace(/^\/+/, ""); // 앞쪽 슬래시 제거 // 파일 경로 시도 const possiblePaths = [ join(process.cwd(), "public", storedPath) ]; // 실제 파일 찾기 let actualPath = null; for (const testPath of possiblePaths) { try { await access(testPath, constants.R_OK); actualPath = testPath; break; } catch (err) { console.log("❌ 경로에 파일 없음:", testPath); } } if (!actualPath) { return NextResponse.json( { error: "File not found on server", details: { path: path, triedPaths: possiblePaths } }, { status: 404 } ); } const fileBuffer = await readFile(actualPath); // MIME 타입 결정 const fileExtension = fileName.split('.').pop()?.toLowerCase() || ''; let contentType = 'application/octet-stream'; // 기본 바이너리 // 확장자에 따른 MIME 타입 매핑 const mimeTypes: Record = { 'pdf': 'application/pdf', 'doc': 'application/msword', 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls': 'application/vnd.ms-excel', 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'ppt': 'application/vnd.ms-powerpoint', 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'txt': 'text/plain', 'csv': 'text/csv', 'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'gif': 'image/gif', }; contentType = mimeTypes[fileExtension] || contentType; // 다운로드용 헤더 설정 const headers = new Headers(); headers.set('Content-Type', contentType); headers.set('Content-Disposition', `attachment; filename="${encodeURIComponent(fileName)}"`); headers.set('Content-Length', fileBuffer.length.toString()); return new NextResponse(fileBuffer, { status: 200, headers, }); } catch (error) { console.error('❌ RFQ 파일 다운로드 오류:', error); return NextResponse.json( { error: 'Failed to download file', details: String(error) }, { status: 500 } ); } }