summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-13 02:07:52 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-13 02:07:52 +0000
commite47c0d8bf032e9da9f2cae1b648649bd33e44589 (patch)
treef3da7c970c03038b57ec47ef9b399d44c9f22267 /lib
parentcc871c6a1138595283de6f12c03519eb7346e55f (diff)
(임수민) 일반계약 템플릿 수정
Diffstat (limited to 'lib')
-rw-r--r--lib/general-contract-template/service.ts97
-rw-r--r--lib/general-contract-template/template/general-contract-template-toolbar-actions.tsx33
2 files changed, 52 insertions, 78 deletions
diff --git a/lib/general-contract-template/service.ts b/lib/general-contract-template/service.ts
index 9b3eda68..37af83ce 100644
--- a/lib/general-contract-template/service.ts
+++ b/lib/general-contract-template/service.ts
@@ -9,7 +9,8 @@ import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { GeneralContractTemplate, generalContractTemplates, users } from "@/db/schema";
-import { deleteFile, saveFile } from "@/lib/file-stroage";
+import { deleteFile, saveFile, saveDRMFile } from "@/lib/file-stroage";
+import { decryptWithServerAction } from "@/components/drm/drmUtils";
import {
selectContractTemplates,
selectContractTemplatesWithUsers,
@@ -223,22 +224,47 @@ export async function saveTemplateFile(templateId: number, formData: FormData) {
return { error: "파일 경로가 없습니다." };
}
- // 파일 저장 로직 (실제 파일 시스템에 저장)
- const { writeFile, mkdir } = await import("fs/promises");
- const { join } = await import("path");
+ // 파일 저장 로직 (DRM 해제 로직 적용)
+ const saveResult = await saveDRMFile(
+ file,
+ decryptWithServerAction,
+ 'general-contract-templates'
+ );
- const bytes = await file.arrayBuffer();
- const buffer = Buffer.from(bytes);
+ if (!saveResult.success) {
+ return { error: saveResult.error || '파일 저장에 실패했습니다.' };
+ }
- // 기존 파일 경로 사용 (덮어쓰기) - general-contract-templates 경로로 통일
- const uploadPath = join(process.cwd(), "public", template.filePath.replace(/^\//, ""));
-
- // 디렉토리 확인 및 생성
- const dirPath = uploadPath.substring(0, uploadPath.lastIndexOf('/'));
- await mkdir(dirPath, { recursive: true });
+ // 기존 파일 경로와 다른 경우에만 파일 경로 업데이트
+ if (template.filePath !== saveResult.publicPath) {
+ // 기존 파일 삭제
+ if (template.filePath) {
+ const deleted = await deleteFile(template.filePath);
+ if (deleted) {
+ console.log(`✅ 기존 파일 삭제됨: ${template.filePath}`);
+ } else {
+ console.log(`⚠️ 기존 파일 삭제 실패: ${template.filePath}`);
+ }
+ }
- // 파일 저장
- await writeFile(uploadPath, buffer);
+ // DB에 새 파일 경로 업데이트
+ await db
+ .update(generalContractTemplates)
+ .set({
+ filePath: saveResult.publicPath,
+ fileName: file.name,
+ updatedAt: new Date(),
+ })
+ .where(eq(generalContractTemplates.id, templateId));
+ } else {
+ // 같은 경로인 경우 수정일시만 업데이트
+ await db
+ .update(generalContractTemplates)
+ .set({
+ updatedAt: new Date(),
+ })
+ .where(eq(generalContractTemplates.id, templateId));
+ }
// 캐시 무효화 (목록/상세 모두 고려)
revalidatePath(`/evcp/general-contract-template/${templateId}`);
@@ -424,40 +450,19 @@ export async function updateTemplate({
let filePath: string | undefined = undefined;
if (file) {
- // 1) 새 파일 저장 (원본 파일명 유지 + 충돌 시 접미사)
- const { mkdir, writeFile, access } = await import('fs/promises');
- const { join, extname, basename } = await import('path');
-
- const ext = extname(file.name);
- const base = basename(file.name, ext)
- .replace(/[<>:"'|?*\\\/]/g, '_')
- .replace(/[\x00-\x1f]/g, '')
- .replace(/\s+/g, ' ')
- .trim()
- .substring(0, 200);
-
- const dirAbs = join(process.cwd(), 'public', 'general-contract-templates');
- await mkdir(dirAbs, { recursive: true });
-
- let candidate = `${base}${ext}`;
- let absPath = join(dirAbs, candidate);
- let counter = 1;
- while (true) {
- try {
- await access(absPath);
- candidate = `${base} (${counter})${ext}`;
- absPath = join(dirAbs, candidate);
- counter += 1;
- } catch {
- break;
- }
+ // 1) 새 파일 저장 (DRM 해제 로직 적용)
+ const saveResult = await saveDRMFile(
+ file,
+ decryptWithServerAction,
+ 'general-contract-templates'
+ );
+
+ if (!saveResult.success) {
+ return { error: saveResult.error || '파일 저장에 실패했습니다.' };
}
- const bytes = await file.arrayBuffer();
- await writeFile(absPath, Buffer.from(bytes));
-
- fileName = candidate;
- filePath = `/general-contract-templates/${candidate}`;
+ fileName = file.name;
+ filePath = saveResult.publicPath;
// 2) 기존 파일 삭제
if (prev.filePath) {
diff --git a/lib/general-contract-template/template/general-contract-template-toolbar-actions.tsx b/lib/general-contract-template/template/general-contract-template-toolbar-actions.tsx
index 03818109..38a83a7f 100644
--- a/lib/general-contract-template/template/general-contract-template-toolbar-actions.tsx
+++ b/lib/general-contract-template/template/general-contract-template-toolbar-actions.tsx
@@ -1,8 +1,7 @@
"use client"
import * as React from "react"
-import { useRouter } from "next/navigation"
-import { Trash2, FileText } from "lucide-react"
+import { Trash2 } from "lucide-react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
@@ -19,10 +18,7 @@ export function GeneralContractTemplateToolbarActions({
selectedRows = [],
onSelectionChange
}: GeneralContractTemplateToolbarActionsProps) {
- const router = useRouter()
- const [isModifyOpen, setIsModifyOpen] = React.useState(false)
const [isDisposeOpen, setIsDisposeOpen] = React.useState(false)
- const [isContractStatusOpen, setIsContractStatusOpen] = React.useState(false)
// 폐기 버튼 클릭
const handleDispose = () => {
@@ -34,22 +30,6 @@ export function GeneralContractTemplateToolbarActions({
setIsDisposeOpen(true)
}
- // 계약현황 버튼 클릭
- const handleContractStatus = () => {
- if (selectedRows.length === 0) {
- toast.error("확인할 문서를 선택해주세요.")
- return
- }
-
- if (selectedRows.length > 1) {
- toast.error("한 번에 하나의 문서만 확인할 수 있습니다.")
- return
- }
-
- // 일반계약관리 페이지로 이동
- router.push(`/evcp/general-contracts`)
- }
-
// 실제 폐기 처리
const handleConfirmDispose = async () => {
try {
@@ -76,17 +56,6 @@ export function GeneralContractTemplateToolbarActions({
{/* 신규등록: 다이얼로그 사용 */}
<AddGeneralContractTemplateDialog />
- {/* 계약현황 버튼 */}
- <Button
- onClick={handleContractStatus}
- variant="outline"
- size="sm"
- className="border-blue-600 text-blue-600 hover:bg-blue-50"
- >
- <FileText className="mr-2 h-4 w-4" />
- 계약현황
- </Button>
-
{/* 폐기 버튼 */}
<Button
onClick={handleDispose}