diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-07 01:44:45 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-07 01:44:45 +0000 |
| commit | 90f79a7a691943a496f67f01c1e493256070e4de (patch) | |
| tree | 37275fde3ae08c2bca384fbbc8eb378de7e39230 /lib/rfqs-tech | |
| parent | fbb3b7f05737f9571b04b0a8f4f15c0928de8545 (diff) | |
(대표님) 변경사항 20250707 10시 43분 - unstaged 변경사항 추가
Diffstat (limited to 'lib/rfqs-tech')
| -rw-r--r-- | lib/rfqs-tech/service.ts | 142 |
1 files changed, 17 insertions, 125 deletions
diff --git a/lib/rfqs-tech/service.ts b/lib/rfqs-tech/service.ts index fac18a43..6989188b 100644 --- a/lib/rfqs-tech/service.ts +++ b/lib/rfqs-tech/service.ts @@ -10,9 +10,6 @@ import { getErrorMessage } from "@/lib/handle-error"; import { GetRfqsSchema, CreateRfqSchema, UpdateRfqSchema, CreateRfqItemSchema, GetMatchedVendorsSchema, UpdateRfqVendorSchema, GetTBESchema, GetCBESchema, createCbeEvaluationSchema } from "./validations"; import { asc, desc, ilike, inArray, and, or, sql, eq, isNull, ne, isNotNull, count } from "drizzle-orm"; import path from "path"; -import fs from "fs/promises"; -import { randomUUID } from "crypto"; -import { writeFile, mkdir } from 'fs/promises' import { join } from 'path' import { vendorResponses, vendorResponsesView, Rfq, rfqs, rfqAttachments, rfqItems, rfqComments, rfqEvaluations, vendorRfqView, vendorTbeView, rfqsView, vendorResponseAttachments, vendorTechnicalResponses, cbeEvaluations, vendorCommercialResponses, vendorResponseCBEView, RfqViewWithItems } from "@/db/schema/rfq"; @@ -27,6 +24,7 @@ import { headers } from 'next/headers'; // DRM 복호화 관련 유틸 import import { decryptWithServerAction } from "@/components/drm/drmUtils"; +import { deleteFile, saveDRMFile, saveFile } from "../file-stroage"; interface InviteVendorsInput { rfqId: number @@ -364,50 +362,21 @@ export async function processRfqAttachments(args: { // 1-3) 파일 삭제 for (const row of rows) { - // filePath: 예) "/rfq/123/...xyz" - const absolutePath = path.join( - process.cwd(), - "public", - row.filePath.replace(/^\/+/, "") // 슬래시 제거 - ); - try { - await fs.unlink(absolutePath); - } catch (err) { - console.error("File remove error:", err); - } + await deleteFile(row.filePath) } } // 2) 새 파일 업로드 if (newFiles.length > 0) { - const rfqDir = path.join("public", "rfq", String(rfqId)); - // 폴더 없으면 생성 - await fs.mkdir(rfqDir, { recursive: true }); - for (const file of newFiles) { - // 2-1) DRM 복호화 시도 ---------------------------------------------------------------------- - // decryptWithServerAction 함수는 오류 처리 및 원본 반환 로직을 포함하고 있음 (해제 실패시 원본 반환) - // 이후 코드가 buffer로 작업하므로 buffer로 전환한다. - const decryptedData = await decryptWithServerAction(file); - const buffer = Buffer.from(decryptedData); - // ----------------------------------------------------------------------------------------- - - - // 2-2) 고유 파일명 - const uniqueName = `${randomUUID()}-${file.name}`; - // 예) "rfq/123/xxx" - const relativePath = path.join("rfq", String(rfqId), uniqueName); - const absolutePath = path.join("public", relativePath); - - // 2-3) 파일 저장 - await fs.writeFile(absolutePath, buffer); + const saveResult = await saveDRMFile(file, decryptWithServerAction, `rfqTech/${rfqId}`) // 2-4) DB Insert await db.insert(rfqAttachments).values({ rfqId, vendorId, fileName: file.name, - filePath: "/" + relativePath.replace(/\\/g, "/"), + filePath: saveResult.publicPath!, // (Windows 경로 대비) }); } @@ -1410,15 +1379,6 @@ export async function inviteTbeVendorsAction(formData: FormData) { throw new Error("Invalid input or no files attached.") } - // /public/rfq/[rfqId] 경로 - const uploadDir = path.join(process.cwd(), "public", "rfq", String(rfqId)) - - // 디렉토리가 없다면 생성 - try { - await fs.mkdir(uploadDir, { recursive: true }) - } catch (err) { - console.error("디렉토리 생성 실패:", err) - } // DB 트랜잭션 await db.transaction(async (tx) => { @@ -1466,21 +1426,14 @@ export async function inviteTbeVendorsAction(formData: FormData) { // 여기서는 "모든 파일"을 RFQ-DIR에 저장 + "각 협력업체"에는 동일 파일 목록을 첨부한다는 예시. const savedFiles = [] for (const file of tbeFiles) { - const originalName = file.name || "tbe-sheet.xlsx" - // 파일명 충돌 방지를 위한 타임스탬프 추가 - const timestamp = new Date().getTime() - const fileName = `${timestamp}-${originalName}` - const savePath = path.join(uploadDir, fileName) - // 파일 ArrayBuffer → Buffer 변환 후 저장 - const arrayBuffer = await file.arrayBuffer() - await fs.writeFile(savePath, Buffer.from(arrayBuffer)) + const saveResult = await saveDRMFile(file, decryptWithServerAction, `rfqTech/${rfqId}`) // 저장 경로 & 파일명 기록 savedFiles.push({ - fileName: originalName, // 원본 파일명으로 첨부 - filePath: `/rfq/${rfqId}/${fileName}`, // public 이하 경로 - absolutePath: savePath, + fileName: file.name, // 원본 파일명으로 첨부 + filePath: saveResult.publicPath, // public 이하 경로 + absolutePath: saveResult.publicPath, }) } @@ -1652,22 +1605,9 @@ export async function createRfqCommentWithAttachments(params: { // 2) 첨부파일 처리 if (files && files.length > 0) { - const rfqDir = path.join(process.cwd(), "public", "rfq", String(rfqId)); - // 폴더 없으면 생성 - await fs.mkdir(rfqDir, { recursive: true }); - for (const file of files) { - const ab = await file.arrayBuffer(); - const buffer = Buffer.from(ab); - // 2-2) 고유 파일명 - const uniqueName = `${randomUUID()}-${file.name}`; - // 예) "rfq/123/xxx" - const relativePath = path.join("rfq", String(rfqId), uniqueName); - const absolutePath = path.join(process.cwd(), "public", relativePath); - - // 2-3) 파일 저장 - await fs.writeFile(absolutePath, buffer); + const saveResult = await saveDRMFile(file, decryptWithServerAction, `rfqTech/${rfqId}`) // DB에 첨부파일 row 생성 await db.insert(rfqAttachments).values({ @@ -1677,7 +1617,7 @@ export async function createRfqCommentWithAttachments(params: { cbeId: cbeId || null, commentId: insertedComment.id, // 새 코멘트와 연결 fileName: file.name, - filePath: "/" + relativePath.replace(/\\/g, "/"), + filePath: saveResult.publicPath!, }) } } @@ -2045,37 +1985,14 @@ export async function uploadTbeResponseFile(formData: FormData) { } } - // 타임스탬프 기반 고유 파일명 생성 - const timestamp = Date.now() - const originalName = file.name - const fileExtension = originalName.split(".").pop() - const fileName = `${originalName.split(".")[0]}-${timestamp}.${fileExtension}` - - // 업로드 디렉토리 및 경로 정의 - const uploadDir = join(process.cwd(), "public", "rfq", "tbe-responses") - - // 디렉토리가 없으면 생성 - try { - await mkdir(uploadDir, { recursive: true }) - } catch (error) { - // 이미 존재하면 무시 - } - - const filePath = join(uploadDir, fileName) - - // 파일을 버퍼로 변환 - const bytes = await file.arrayBuffer() - const buffer = Buffer.from(bytes) - - // 파일을 서버에 저장 - await writeFile(filePath, buffer) + const saveResult = await saveFile({file, directory:`rfqTech/${rfqId}/tbe-responses`}) // 먼저 vendorTechnicalResponses 테이블에 엔트리 생성 const technicalResponse = await db.insert(vendorTechnicalResponses) .values({ responseId: vendorResponseId, summary: "TBE 응답 파일 업로드", // 필요에 따라 수정 - notes: `파일명: ${originalName}`, + notes: `파일명: ${file.name}`, responseStatus:"SUBMITTED" }) .returning({ id: vendorTechnicalResponses.id }); @@ -2083,9 +2000,6 @@ export async function uploadTbeResponseFile(formData: FormData) { // 생성된 기술 응답 ID 가져오기 const technicalResponseId = technicalResponse[0].id; - // 파일 정보를 데이터베이스에 저장 - const dbFilePath = `rfq/tbe-responses/${fileName}` - // vendorResponseAttachments 테이블 스키마에 맞게 데이터 삽입 await db.insert(vendorResponseAttachments) .values({ @@ -2096,8 +2010,8 @@ export async function uploadTbeResponseFile(formData: FormData) { // vendorId와 evaluationId 필드가 테이블에 있다면 포함, 없다면 제거 // vendorId: vendorId, // evaluationId: evaluationId, - fileName: originalName, - filePath: dbFilePath, + fileName: file.name, + filePath: saveResult.publicPath!, uploadedAt: new Date(), }); @@ -2902,18 +2816,6 @@ export async function createCbeEvaluation(formData: FormData) { const files = formData.getAll("files") as File[] const hasFiles = files && files.length > 0 && files[0].size > 0 - // 파일 저장을 위한 디렉토리 생성 (파일이 있는 경우에만) - let uploadDir = "" - if (hasFiles) { - uploadDir = path.join(process.cwd(), "public", "rfq", String(rfqId)) - try { - await fs.mkdir(uploadDir, { recursive: true }) - } catch (err) { - console.error("디렉토리 생성 실패:", err) - return { error: "파일 업로드를 위한 디렉토리 생성에 실패했습니다." } - } - } - // 첨부 파일 정보를 저장할 배열 const attachments: { filename: string; path: string }[] = [] @@ -2921,23 +2823,13 @@ export async function createCbeEvaluation(formData: FormData) { if (hasFiles) { for (const file of files) { if (file.size > 0) { - const originalFilename = file.name - const fileExtension = path.extname(originalFilename) - const timestamp = new Date().getTime() - const safeFilename = `cbe-${rfqId}-${timestamp}${fileExtension}` - const filePath = path.join("rfq", String(rfqId), safeFilename) - const fullPath = path.join(process.cwd(), "public", filePath) - try { - // File을 ArrayBuffer로 변환하여 파일 시스템에 저장 - const arrayBuffer = await file.arrayBuffer() - const buffer = Buffer.from(arrayBuffer) - await fs.writeFile(fullPath, buffer) + const saveResult = await saveDRMFile(file, decryptWithServerAction, `rfqTech/${rfqId}`) // 첨부 파일 정보 추가 attachments.push({ - filename: originalFilename, - path: fullPath, // 이메일 첨부를 위한 전체 경로 + filename: file.name, + path: saveResult.publicPath!, // 이메일 첨부를 위한 전체 경로 }) } catch (err) { console.error(`파일 저장 실패:`, err) |
