summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-06 20:11:15 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-06 20:11:15 +0900
commitd20a3b0f899bc55369c2410ec7244c24391928da (patch)
tree80196bdf99b7b3a9d0834f26e0700d7e7c3a066b
parent4c07f977c951cd99dd50d3bdaad0437e3dd55e6d (diff)
(김준회) 벤더 견적 응답: 첨부파일 다운로드시 암호화 해제해서 다운로드 받도록 변경
-rw-r--r--lib/rfq-last/vendor-response/editor/attachments-upload.tsx50
-rw-r--r--lib/rfq-last/vendor-response/rfq-attachments-dialog.tsx61
2 files changed, 90 insertions, 21 deletions
diff --git a/lib/rfq-last/vendor-response/editor/attachments-upload.tsx b/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
index 96a88ef7..be9263f5 100644
--- a/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
+++ b/lib/rfq-last/vendor-response/editor/attachments-upload.tsx
@@ -40,6 +40,7 @@ import { formatBytes } from "@/lib/utils"
import { cn } from "@/lib/utils"
import { toast } from "sonner"
import { deleteVendorResponseAttachment } from "../../service"
+import { decryptWithServerAction } from "@/components/drm/drmUtils"
interface FileWithType extends File {
attachmentType?: "구매" | "설계"
@@ -254,6 +255,53 @@ export default function AttachmentsUpload({
setDeleteDialogOpen(false)
setFileToDelete(null)
}
+
+ // 기존 첨부파일 다운로드 핸들러 (DRM 복호화 적용)
+ const handleExistingFileDownload = async (file: any) => {
+ try {
+ // 1. 파일 가져오기
+ const fileUrl = file.filePath.startsWith('http')
+ ? file.filePath
+ : `${window.location.origin}${file.filePath}`
+
+ toast.loading(`파일 다운로드 준비 중...`, { id: `download-${file.id}` })
+
+ const response = await fetch(fileUrl)
+ if (!response.ok) {
+ throw new Error(`파일 다운로드 실패: ${response.status}`)
+ }
+
+ // 2. Blob을 File로 변환
+ const blob = await response.blob()
+ const fileObj = new File([blob], file.originalFileName, { type: blob.type })
+
+ // 3. DRM 복호화
+ toast.loading(`파일 복호화 중...`, { id: `download-${file.id}` })
+ const decryptedBuffer = await decryptWithServerAction(fileObj)
+
+ // 4. 복호화된 파일 다운로드
+ const decryptedBlob = new Blob([decryptedBuffer], { type: blob.type })
+ const downloadUrl = URL.createObjectURL(decryptedBlob)
+
+ const link = document.createElement('a')
+ link.href = downloadUrl
+ link.download = file.originalFileName
+ link.style.display = 'none'
+
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ // 메모리 정리
+ setTimeout(() => URL.revokeObjectURL(downloadUrl), 100)
+
+ toast.success(`파일 다운로드 완료: ${file.originalFileName}`, { id: `download-${file.id}` })
+ } catch (error) {
+ console.error("파일 다운로드 오류:", error)
+ const errorMessage = error instanceof Error ? error.message : "파일 다운로드에 실패했습니다"
+ toast.error(errorMessage, { id: `download-${file.id}` })
+ }
+ }
// 파일 아이콘 가져오기
const getFileIcon = (fileName: string) => {
@@ -509,7 +557,7 @@ export default function AttachmentsUpload({
type="button"
variant="ghost"
size="sm"
- onClick={() => window.open(file.filePath, '_blank')}
+ onClick={() => handleExistingFileDownload(file)}
>
<Download className="h-4 w-4" />
</Button>
diff --git a/lib/rfq-last/vendor-response/rfq-attachments-dialog.tsx b/lib/rfq-last/vendor-response/rfq-attachments-dialog.tsx
index 3ca01191..cc7aaba9 100644
--- a/lib/rfq-last/vendor-response/rfq-attachments-dialog.tsx
+++ b/lib/rfq-last/vendor-response/rfq-attachments-dialog.tsx
@@ -26,6 +26,7 @@ import { toast } from "sonner"
import { RfqsLastView } from "@/db/schema"
import { getRfqAttachmentsAction } from "../service"
import { downloadFile, quickPreview, smartFileAction, formatFileSize, getFileInfo } from "@/lib/file-download"
+import { decryptWithServerAction } from "@/components/drm/drmUtils"
// 첨부파일 타입
interface RfqAttachment {
@@ -132,34 +133,54 @@ export function RfqAttachmentsDialog({ isOpen, onClose, rfqData }: RfqAttachment
loadAttachments()
}, [isOpen, rfqData.id])
- // 파일 다운로드 핸들러
+ // 파일 다운로드 핸들러 (DRM 복호화 적용)
const handleDownload = async (attachment: RfqAttachment) => {
const attachmentId = attachment.attachmentId
setDownloadingFiles(prev => new Set([...prev, attachmentId]))
try {
- const result = await downloadFile(
- attachment.filePath,
- attachment.originalFileName,
- {
- action: 'download',
- showToast: true,
- showSuccessToast: true,
- onSuccess: (fileName, fileSize) => {
- console.log(`다운로드 완료: ${fileName} (${formatFileSize(fileSize || 0)})`)
- },
- onError: (error) => {
- console.error(`다운로드 실패: ${error}`)
- }
- }
- )
-
- if (!result.success) {
- console.error("다운로드 결과:", result)
+ // 1. 파일 가져오기
+ const fileUrl = attachment.filePath.startsWith('http')
+ ? attachment.filePath
+ : `${window.location.origin}${attachment.filePath}`
+
+ toast.loading(`파일 다운로드 준비 중...`, { id: `download-${attachmentId}` })
+
+ const response = await fetch(fileUrl)
+ if (!response.ok) {
+ throw new Error(`파일 다운로드 실패: ${response.status}`)
}
+
+ // 2. Blob을 File로 변환
+ const blob = await response.blob()
+ const file = new File([blob], attachment.originalFileName, { type: blob.type })
+
+ // 3. DRM 복호화
+ toast.loading(`파일 복호화 중...`, { id: `download-${attachmentId}` })
+ const decryptedBuffer = await decryptWithServerAction(file)
+
+ // 4. 복호화된 파일 다운로드
+ const decryptedBlob = new Blob([decryptedBuffer], { type: blob.type })
+ const downloadUrl = URL.createObjectURL(decryptedBlob)
+
+ const link = document.createElement('a')
+ link.href = downloadUrl
+ link.download = attachment.originalFileName
+ link.style.display = 'none'
+
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ // 메모리 정리
+ setTimeout(() => URL.revokeObjectURL(downloadUrl), 100)
+
+ toast.success(`파일 다운로드 완료: ${attachment.originalFileName}`, { id: `download-${attachmentId}` })
+ console.log(`다운로드 완료: ${attachment.originalFileName} (${formatFileSize(decryptedBlob.size)})`)
} catch (error) {
console.error("파일 다운로드 오류:", error)
- toast.error("파일 다운로드에 실패했습니다")
+ const errorMessage = error instanceof Error ? error.message : "파일 다운로드에 실패했습니다"
+ toast.error(errorMessage, { id: `download-${attachmentId}` })
} finally {
setDownloadingFiles(prev => {
const newSet = new Set(prev)