"use server" import { getErrorMessage } from "@/lib/handle-error" import { desc, or, eq } from "drizzle-orm" import db from "@/db/db" import { pageInformation, menuAssignments, users } from "@/db/schema" import { saveDRMFile } from "@/lib/file-stroage" import { decryptWithServerAction } from "@/components/drm/drmUtils" import type { UpdateInformationSchema } from "./validations" import { getInformationByPagePathWithAttachments, updateInformation, getInformationWithAttachments, addInformationAttachment, deleteInformationAttachment, getAttachmentById } from "./repository" import type { PageInformation, InformationAttachment } from "@/db/schema/information" // 간단한 인포메이션 목록 조회 (페이지네이션 없이 전체 조회) export async function getInformationLists() { try { // 전체 데이터 조회 (클라이언트에서 검색 처리, 생성자/수정자 정보 포함) const data = await db .select({ id: pageInformation.id, pagePath: pageInformation.pagePath, pageName: pageInformation.pageName, informationContent: pageInformation.informationContent, isActive: pageInformation.isActive, createdBy: pageInformation.createdBy, createdAt: pageInformation.createdAt, updatedBy: pageInformation.updatedBy, updatedAt: pageInformation.updatedAt, updatedByName: users.name, updatedByEmail: users.email, }) .from(pageInformation) .leftJoin(users, eq(pageInformation.updatedBy, users.id)) .orderBy(desc(pageInformation.createdAt)) return { data } } catch (err) { console.error("Failed to get information lists:", err) return { data: [] } } } // 페이지별 인포메이션 조회 (첨부파일 포함) export async function getPageInformation(pagePath: string) { try { console.log('🔍 Information Service - 조회 시작:', { pagePath }) const result = await getInformationByPagePathWithAttachments(pagePath) console.log('📊 Information Service - 조회 결과:', { pagePath, found: !!result, resultData: result ? { id: result.id, pagePath: result.pagePath, pageName: result.pageName, attachmentsCount: result.attachments?.length || 0 } : null }) return result } catch (error) { console.error(`Failed to get information for page ${pagePath}:`, error) return null } } // 페이지별 인포메이션 조회 (직접 호출용) export async function getPageInformationDirect(pagePath: string) { return await getPageInformation(pagePath) } // 인포메이션 수정 (내용과 첨부파일만) export async function updateInformationData(input: UpdateInformationSchema, userId?: string) { try { const { id, ...updateData } = input // 수정 가능한 필드만 허용 const allowedFields = { informationContent: updateData.informationContent, isActive: updateData.isActive, updatedBy: userId ? parseInt(userId) : null, updatedAt: new Date() } const result = await updateInformation(id, allowedFields) if (!result) { return { success: false, message: "인포메이션을 찾을 수 없거나 수정에 실패했습니다." } } // 캐시 무효화 제거됨 return { success: true, message: "인포메이션이 성공적으로 수정되었습니다." } } catch (error) { console.error("Failed to update information:", error) return { success: false, message: getErrorMessage(error) } } } // ID로 인포메이션 조회 (첨부파일 포함) export async function getInformationDetail(id: number) { try { return await getInformationWithAttachments(id) } catch (error) { console.error(`Failed to get information detail for id ${id}:`, error) return null } } // 인포메이션 편집 권한 확인 export async function checkInformationEditPermission(pagePath: string, userId: string): Promise { try { // pagePath 정규화 (앞의 / 제거) const normalizedPagePath = pagePath.startsWith('/') ? pagePath.slice(1) : pagePath // pagePath를 menuPath로 변환 (pagePath가 menuPath의 마지막 부분이라고 가정) // 예: pagePath "vendor-list" -> menuPath "/evcp/vendor-list" 또는 "/partners/vendor-list" const menuPathQueries = [ `/evcp/${normalizedPagePath}`, `/partners/${normalizedPagePath}`, `/${normalizedPagePath}`, // 루트 경로 normalizedPagePath, // 정확한 매칭 `/${pagePath}`, // 원본 경로도 체크 pagePath // 원본 경로 정확한 매칭 ] // menu_assignments에서 해당 pagePath와 매칭되는 메뉴 찾기 const menuAssignment = await db .select() .from(menuAssignments) .where( or( ...menuPathQueries.map(path => eq(menuAssignments.menuPath, path)) ) ) .limit(1) if (menuAssignment.length === 0) { // 매칭되는 메뉴가 없으면 권한 없음 return false } const assignment = menuAssignment[0] const userIdNumber = parseInt(userId) // 현재 사용자가 manager1 또는 manager2인지 확인 return assignment.manager1Id === userIdNumber || assignment.manager2Id === userIdNumber } catch (error) { console.error("Failed to check information edit permission:", error) return false } } // 권한 확인 (직접 호출용) export async function getEditPermissionDirect(pagePath: string, userId: string) { return await checkInformationEditPermission(pagePath, userId) } // menu_assignments 기반으로 page_information 동기화 export async function syncInformationFromMenuAssignments() { try { // menu_assignments에서 모든 메뉴 가져오기 const menuItems = await db.select().from(menuAssignments); let processedCount = 0; // upsert를 사용하여 각 메뉴 항목 처리 for (const menu of menuItems) { try { // 맨 앞의 / 제거하여 pagePath 정규화 const normalizedPagePath = menu.menuPath.startsWith('/') ? menu.menuPath.slice(1) : menu.menuPath; await db.insert(pageInformation) .values({ pagePath: normalizedPagePath, pageName: menu.menuTitle, informationContent: "", isActive: true // 기본값으로 활성화 }) .onConflictDoUpdate({ target: pageInformation.pagePath, set: { pageName: menu.menuTitle, updatedAt: new Date() } }); processedCount++; } catch (itemError: any) { console.warn(`메뉴 항목 처리 실패: ${menu.menuPath}`, itemError); continue; } } // 캐시 무효화 제거됨 return { success: true, message: `페이지 정보 동기화 완료: ${processedCount}개 처리됨` }; } catch (error) { console.error("Information 동기화 오류:", error); return { success: false, message: "페이지 정보 동기화 중 오류가 발생했습니다." }; } } // 첨부파일 업로드 export async function uploadInformationAttachment(formData: FormData) { try { const informationId = parseInt(formData.get("informationId") as string) const file = formData.get("file") as File if (!informationId || !file) { return { success: false, message: "필수 매개변수가 누락되었습니다." } } // 파일 저장 const saveResult = await saveDRMFile( file, decryptWithServerAction, `information/${informationId}`, // userId는 필요시 추가 ) if (!saveResult.success) { return { success: false, message: saveResult.error || "파일 저장에 실패했습니다." } } // DB에 첨부파일 정보 저장 const attachment = await addInformationAttachment({ informationId, fileName: file.name, filePath: saveResult.publicPath || "", fileSize: saveResult.fileSize ? String(saveResult.fileSize) : String(file.size) }) if (!attachment) { return { success: false, message: "첨부파일 정보 저장에 실패했습니다." } } // 캐시 무효화 제거됨 return { success: true, message: "첨부파일이 성공적으로 업로드되었습니다.", data: attachment } } catch (error) { console.error("Failed to upload attachment:", error) return { success: false, message: getErrorMessage(error) } } } // 첨부파일 삭제 export async function deleteInformationAttachmentAction(attachmentId: number) { try { const attachment = await getAttachmentById(attachmentId) if (!attachment) { return { success: false, message: "첨부파일을 찾을 수 없습니다." } } // DB에서 삭제 const deleted = await deleteInformationAttachment(attachmentId) if (!deleted) { return { success: false, message: "첨부파일 삭제에 실패했습니다." } } // 캐시 무효화 제거됨 return { success: true, message: "첨부파일이 성공적으로 삭제되었습니다." } } catch (error) { console.error("Failed to delete attachment:", error) return { success: false, message: getErrorMessage(error) } } } // 첨부파일 다운로드 export async function downloadInformationAttachment(attachmentId: number) { try { const attachment = await getAttachmentById(attachmentId) if (!attachment) { return { success: false, message: "첨부파일을 찾을 수 없습니다." } } // 파일 다운로드 (클라이언트에서 사용) return { success: true, data: { filePath: attachment.filePath, fileName: attachment.fileName, fileSize: attachment.fileSize } } } catch (error) { console.error("Failed to download attachment:", error) return { success: false, message: getErrorMessage(error) } } }