diff options
| author | rlaks5757 <rlaks5757@gmail.com> | 2025-03-27 17:48:36 +0900 |
|---|---|---|
| committer | rlaks5757 <rlaks5757@gmail.com> | 2025-03-27 17:48:36 +0900 |
| commit | 773918229ccb14c0d00798fbbf2b2be0130a8251 (patch) | |
| tree | ab9e200e65cc471ec139cd8482bde70a3b0a105f /app/api/tbe-download/route.ts | |
| parent | 92ddb4f13d48cbf344dc2bf63df4457b3c713608 (diff) | |
| parent | 34bbeb86c1a8d24b5f526710889b5e54d699cfd0 (diff) | |
merge complete
Diffstat (limited to 'app/api/tbe-download/route.ts')
| -rw-r--r-- | app/api/tbe-download/route.ts | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/app/api/tbe-download/route.ts b/app/api/tbe-download/route.ts new file mode 100644 index 00000000..12e42920 --- /dev/null +++ b/app/api/tbe-download/route.ts @@ -0,0 +1,121 @@ +// 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<string, string> = { + '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 } + ); + } +}
\ No newline at end of file |
