summaryrefslogtreecommitdiff
path: root/app/api/upload
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-04-28 02:13:30 +0000
commitef4c533ebacc2cdc97e518f30e9a9350004fcdfb (patch)
tree345251a3ed0f4429716fa5edaa31024d8f4cb560 /app/api/upload
parent9ceed79cf32c896f8a998399bf1b296506b2cd4a (diff)
~20250428 작업사항
Diffstat (limited to 'app/api/upload')
-rw-r--r--app/api/upload/basicContract/chunk/route.ts71
-rw-r--r--app/api/upload/basicContract/complete/route.ts37
-rw-r--r--app/api/upload/signed-contract/route.ts57
3 files changed, 165 insertions, 0 deletions
diff --git a/app/api/upload/basicContract/chunk/route.ts b/app/api/upload/basicContract/chunk/route.ts
new file mode 100644
index 00000000..7100988b
--- /dev/null
+++ b/app/api/upload/basicContract/chunk/route.ts
@@ -0,0 +1,71 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { mkdir, writeFile, appendFile } from 'fs/promises';
+import path from 'path';
+import crypto from 'crypto';
+
+export async function POST(request: NextRequest) {
+ try {
+ const formData = await request.formData();
+
+ const chunk = formData.get('chunk') as File;
+ const filename = formData.get('filename') as string;
+ const chunkIndex = parseInt(formData.get('chunkIndex') as string);
+ const totalChunks = parseInt(formData.get('totalChunks') as string);
+ const fileId = formData.get('fileId') as string;
+
+ if (!chunk || !filename || isNaN(chunkIndex) || isNaN(totalChunks) || !fileId) {
+ return NextResponse.json({ success: false, error: '필수 매개변수가 누락되었습니다' }, { status: 400 });
+ }
+
+ // 임시 디렉토리 생성
+ const tempDir = path.join(process.cwd(), 'temp', fileId);
+ await mkdir(tempDir, { recursive: true });
+
+ // 청크 파일 저장
+ const chunkPath = path.join(tempDir, `chunk-${chunkIndex}`);
+ const buffer = Buffer.from(await chunk.arrayBuffer());
+ await writeFile(chunkPath, buffer);
+
+ // 마지막 청크인 경우 모든 청크를 합쳐 최종 파일 생성
+ if (chunkIndex === totalChunks - 1) {
+ const uploadDir = path.join(process.cwd(), "public", "basicContract", "template");
+ await mkdir(uploadDir, { recursive: true });
+
+ // 파일명 생성
+ const timestamp = Date.now();
+ const randomHash = crypto.createHash('md5')
+ .update(`${filename}-${timestamp}`)
+ .digest('hex')
+ .substring(0, 8);
+ const hashedFileName = `${timestamp}-${randomHash}${path.extname(filename)}`;
+ const finalPath = path.join(uploadDir, hashedFileName);
+
+ // 모든 청크 병합
+ await writeFile(finalPath, Buffer.alloc(0)); // 빈 파일 생성
+ for (let i = 0; i < totalChunks; i++) {
+ const chunkData = await require('fs/promises').readFile(path.join(tempDir, `chunk-${i}`));
+ await appendFile(finalPath, chunkData);
+ }
+
+ // 임시 파일 정리 (비동기로 처리)
+ require('fs/promises').rm(tempDir, { recursive: true, force: true })
+ .catch((e: unknown) => console.error('청크 정리 오류:', e));
+
+ return NextResponse.json({
+ success: true,
+ fileName: filename,
+ filePath: `/basicContract/template/${hashedFileName}`
+ });
+ }
+
+ return NextResponse.json({
+ success: true,
+ chunkIndex,
+ message: `청크 ${chunkIndex + 1}/${totalChunks} 업로드 완료`
+ });
+
+ } catch (error) {
+ console.error('청크 업로드 오류:', error);
+ return NextResponse.json({ success: false, error: '서버 오류' }, { status: 500 });
+ }
+} \ No newline at end of file
diff --git a/app/api/upload/basicContract/complete/route.ts b/app/api/upload/basicContract/complete/route.ts
new file mode 100644
index 00000000..6398c5eb
--- /dev/null
+++ b/app/api/upload/basicContract/complete/route.ts
@@ -0,0 +1,37 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { createBasicContractTemplate } from '@/lib/basic-contract/service';
+import { revalidatePath ,revalidateTag} from 'next/cache';
+
+export async function POST(request: NextRequest) {
+ try {
+ const { templateName,validityPeriod, status, fileName, filePath } = await request.json();
+
+ if (!templateName || !fileName || !filePath) {
+ return NextResponse.json({ success: false, error: '필수 정보가 누락되었습니다' }, { status: 400 });
+ }
+
+ // DB에 저장
+ const { data, error } = await createBasicContractTemplate({
+ templateName,
+ validityPeriod,
+ status,
+ fileName,
+ filePath
+ });
+
+
+ revalidatePath('/evcp/basic-contract-templates');
+ revalidatePath('/'); // 루트 경로 무효화도 시도
+ revalidateTag("basic-contract-templates");
+
+ if (error) {
+ throw new Error(error);
+ }
+
+ return NextResponse.json({ success: true, data });
+
+ } catch (error) {
+ console.error('템플릿 저장 오류:', error);
+ return NextResponse.json({ success: false, error: '서버 오류' }, { status: 500 });
+ }
+} \ No newline at end of file
diff --git a/app/api/upload/signed-contract/route.ts b/app/api/upload/signed-contract/route.ts
new file mode 100644
index 00000000..f26e20ba
--- /dev/null
+++ b/app/api/upload/signed-contract/route.ts
@@ -0,0 +1,57 @@
+// app/api/upload/signed-contract/route.ts
+import { NextRequest, NextResponse } from 'next/server';
+import fs from 'fs/promises';
+import path from 'path';
+import { v4 as uuidv4 } from 'uuid';
+import db from "@/db/db";
+import { basicContract } from '@/db/schema';
+import { eq } from 'drizzle-orm';
+import { revalidateTag } from 'next/cache';
+
+export async function POST(request: NextRequest) {
+ try {
+ const formData = await request.formData();
+ const file = formData.get('file') as File;
+ const tableRowId = parseInt(formData.get('tableRowId') as string);
+ const templateName = formData.get('templateName') as string;
+
+ if (!file || !tableRowId || !templateName) {
+ return NextResponse.json({ result: false, error: '필수 파라미터가 누락되었습니다.' }, { status: 400 });
+ }
+
+ const originalName = `${tableRowId}_${templateName}`;
+ const ext = path.extname(originalName);
+ const uniqueName = uuidv4() + ext;
+
+ const publicDir = path.join(process.cwd(), "public", "basicContract");
+ const relativePath = `/basicContract/${uniqueName}`;
+ const absolutePath = path.join(publicDir, uniqueName);
+ const buffer = Buffer.from(await file.arrayBuffer());
+
+ await fs.mkdir(publicDir, { recursive: true });
+ await fs.writeFile(absolutePath, buffer);
+
+ await db.transaction(async (tx) => {
+ await tx
+ .update(basicContract)
+ .set({
+ status: "COMPLETED",
+ fileName: originalName,
+ filePath: relativePath,
+ updatedAt: new Date(),
+ completedAt: new Date()
+ })
+ .where(eq(basicContract.id, tableRowId));
+ });
+
+ // 캐시 무효화
+ revalidateTag("basic-contract-requests");
+ revalidateTag("basicContractView-vendor");
+
+ return NextResponse.json({ result: true });
+ } catch (error) {
+ console.error('서명된 계약서 저장 오류:', error);
+ const errorMessage = error instanceof Error ? error.message : "알 수 없는 오류";
+ return NextResponse.json({ result: false, error: errorMessage }, { status: 500 });
+ }
+} \ No newline at end of file