summaryrefslogtreecommitdiff
path: root/lib/vendor-document-list/dolce-upload-service.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-08-06 04:25:00 +0000
committerjoonhoekim <26rote@gmail.com>2025-08-06 04:25:00 +0000
commit0e68be98b4ad4691af77232cb0b02b17af825ba3 (patch)
tree09dd9152c87a9c21343e6a1562c959a828e2b462 /lib/vendor-document-list/dolce-upload-service.ts
parentde2ac5a2860bc25180971e7a11f852d9d44675b7 (diff)
(김준회) 문서/도서 리스트 및 제출(조선) 메뉴 디버깅(dolce)
- attachment revisionId 누락건 해결 - crypto 모듈에서 deprecated des-ecb 알고리즘 사용을 위한 추가 처리 - enhancedDocumentsView에 projectId 추가 - route에서 contractId -> projectId 사용하도록 변경
Diffstat (limited to 'lib/vendor-document-list/dolce-upload-service.ts')
-rw-r--r--lib/vendor-document-list/dolce-upload-service.ts87
1 files changed, 82 insertions, 5 deletions
diff --git a/lib/vendor-document-list/dolce-upload-service.ts b/lib/vendor-document-list/dolce-upload-service.ts
index d0db9f2f..2d6a83c6 100644
--- a/lib/vendor-document-list/dolce-upload-service.ts
+++ b/lib/vendor-document-list/dolce-upload-service.ts
@@ -4,6 +4,7 @@ import { documents, revisions, documentAttachments, contracts, projects, vendors
import { eq, and, desc, sql, inArray, min } from "drizzle-orm"
import { v4 as uuidv4 } from "uuid"
import path from "path"
+import * as crypto from "crypto"
export interface DOLCEUploadResult {
success: boolean
@@ -94,7 +95,7 @@ function getFileReaderConfig(): FileReaderConfig {
};
} else {
return {
- baseDir: path.join(process.cwd(), "public"), // 개발환경 public 폴더
+ baseDir: process.cwd(), // 개발환경 현재 디렉토리
isProduction: false,
};
}
@@ -215,7 +216,7 @@ class DOLCEUploadService {
/**
* 계약 정보 조회
*/
- private async getContractInfo(revisionIds: number) {
+ private async getContractInfo(projectId: number) {
const [result] = await db
.select({
projectCode: projects.code,
@@ -225,7 +226,7 @@ class DOLCEUploadService {
.from(contracts)
.innerJoin(projects, eq(contracts.projectId, projects.id))
.innerJoin(vendors, eq(contracts.vendorId, vendors.id))
- .where(eq(contracts.projectId, revisionIds))
+ .where(eq(contracts.projectId, projectId))
.limit(1)
return result
@@ -421,6 +422,18 @@ private async uploadFiles(
console.log(`✅ File uploaded successfully: ${attachment.fileName} -> ${dolceFilePath}`)
console.log(`✅ DB updated for attachment ID: ${attachment.id}`)
+ // 🧪 DOLCE 업로드 확인 테스트
+ try {
+ const testResult = await this.testDOLCEFileDownload(fileId, userId, attachment.fileName)
+ if (testResult.success) {
+ console.log(`✅ DOLCE 업로드 확인 성공: ${attachment.fileName}`)
+ } else {
+ console.warn(`⚠️ DOLCE 업로드 확인 실패: ${attachment.fileName} - ${testResult.error}`)
+ }
+ } catch (testError) {
+ console.warn(`⚠️ DOLCE 업로드 확인 중 오류: ${attachment.fileName}`, testError)
+ }
+
} catch (error) {
console.error(`❌ File upload failed for ${attachment.fileName}:`, error)
throw error
@@ -443,7 +456,7 @@ private async uploadFiles(
private async finalizeUploadResult(resultDataArray: ResultData[]): Promise<void> {
- const url = `${this.UPLOAD_SERVICE_URL}/PWPUploadResultService.ashx`
+ const url = `${this.BASE_URL}/PWPUploadResultService.ashx?`
try {
const jsonData = JSON.stringify(resultDataArray)
@@ -783,7 +796,7 @@ private transformToDoLCEDocument(
// ✅ DB에 저장된 경로 형태: "/documents/[uuid].ext"
// 개발: public/documents/[uuid].ext
// 프로덕션: /evcp_nas/documents/[uuid].ext
- actualFilePath = path.join(config.baseDir, filePath.substring(1)); // 앞의 '/' 제거
+ actualFilePath = path.join(config.baseDir, 'public', filePath.substring(1)); // 앞의 '/' 제거
console.log(`📁 documents 경로 처리: ${filePath} → ${actualFilePath}`);
}
@@ -856,6 +869,70 @@ private transformToDoLCEDocument(
const enabled = process.env.DOLCE_UPLOAD_ENABLED
return enabled === 'true' || enabled === '1'
}
+
+ /**
+ * DOLCE 업로드 확인 테스트 (업로드 후 파일이 DOLCE에 존재하는지 확인)
+ */
+ private async testDOLCEFileDownload(
+ fileId: string,
+ userId: string,
+ fileName: string
+ ): Promise<{ success: boolean; downloadUrl?: string; error?: string }> {
+ try {
+ // DES 암호화 (C# DESCryptoServiceProvider 호환)
+ const DES_KEY = Buffer.from("4fkkdijg", "ascii")
+
+ // 암호화 문자열 생성: FileId↔UserId↔FileName
+ const encryptString = `${fileId}↔${userId}↔${fileName}`
+
+ // DES 암호화 (createCipheriv 사용)
+ const cipher = crypto.createCipheriv('des-ecb', DES_KEY, '')
+ cipher.setAutoPadding(true)
+ let encrypted = cipher.update(encryptString, 'utf8', 'base64')
+ encrypted += cipher.final('base64')
+ const encryptedKey = encrypted.replace(/\+/g, '|||')
+
+ const downloadUrl = `${process.env.DOLCE_DOWNLOAD_URL}?key=${encryptedKey}` || `http://60.100.99.217:1111/Download.aspx?key=${encryptedKey}`
+
+ console.log(`🧪 DOLCE 파일 다운로드 테스트:`)
+ console.log(` 파일명: ${fileName}`)
+ console.log(` FileId: ${fileId}`)
+ console.log(` UserId: ${userId}`)
+ console.log(` 암호화 키: ${encryptedKey}`)
+ console.log(` 다운로드 URL: ${downloadUrl}`)
+
+ const response = await fetch(downloadUrl, {
+ method: 'GET',
+ headers: {
+ 'User-Agent': 'DOLCE-Integration-Service'
+ }
+ })
+
+ if (!response.ok) {
+ console.error(`❌ DOLCE 파일 다운로드 테스트 실패: HTTP ${response.status}`)
+ return {
+ success: false,
+ downloadUrl,
+ error: `HTTP ${response.status}`
+ }
+ }
+
+ const buffer = Buffer.from(await response.arrayBuffer())
+ console.log(`✅ DOLCE 파일 다운로드 테스트 성공: ${fileName} (${buffer.length} bytes)`)
+
+ return {
+ success: true,
+ downloadUrl
+ }
+
+ } catch (error) {
+ console.error(`❌ DOLCE 파일 다운로드 테스트 실패: ${fileName}`, error)
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error'
+ }
+ }
+ }
}
export const dolceUploadService = new DOLCEUploadService()