From 9da494b0e3bbe7b513521d0915510fe9ee376b8b Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 21 Jul 2025 07:19:52 +0000 Subject: (대표님, 최겸) 작업사항 - 이메일 템플릿, 메일링, 기술영업 요구사항 반영 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/mail/service.ts | 380 ---------------------------------------------------- 1 file changed, 380 deletions(-) delete mode 100644 lib/mail/service.ts (limited to 'lib/mail/service.ts') diff --git a/lib/mail/service.ts b/lib/mail/service.ts deleted file mode 100644 index cbd02953..00000000 --- a/lib/mail/service.ts +++ /dev/null @@ -1,380 +0,0 @@ -'use server'; - -import fs from 'fs'; -import path from 'path'; -import handlebars from 'handlebars'; -import i18next from 'i18next'; -import resourcesToBackend from 'i18next-resources-to-backend'; -import { getOptions } from '@/i18n/settings'; - -// Types -export interface TemplateFile { - name: string; - content: string; - lastModified: string; - path: string; -} - -interface UpdateTemplateRequest { - name: string; - content: string; -} - -interface TemplateValidationResult { - isValid: boolean; - errors: string[]; - warnings: string[]; -} - -// Configuration -const baseDir = path.join(process.cwd(), 'lib', 'mail'); -const templatesDir = path.join(baseDir, 'templates'); - -let initialized = false; - -function getFilePath(name: string): string { - const fileName = name.endsWith('.hbs') ? name : `${name}.hbs`; - return path.join(templatesDir, fileName); -} - -// Initialization -async function initializeAsync(): Promise { - if (initialized) return; - - try { - // i18next 초기화 (서버 사이드) - if (!i18next.isInitialized) { - await i18next - .use(resourcesToBackend((language: string, namespace: string) => - import(`@/i18n/locales/${language}/${namespace}.json`) - )) - .init(getOptions()); - } - - // Handlebars 헬퍼 등록 - registerHandlebarsHelpers(); - initialized = true; - } catch (error) { - console.error('Failed to initialize TemplateService:', error); - // 초기화 실패해도 헬퍼는 등록 - registerHandlebarsHelpers(); - initialized = true; - } -} - -async function ensureInitialized(): Promise { - if (initialized) return; - await initializeAsync(); -} - -function registerHandlebarsHelpers(): void { - // i18n 번역 헬퍼 - handlebars.registerHelper('t', function(key: string, options: { hash?: Record }) { - return i18next.t(key, options.hash || {}); - }); - - // 날짜 포맷 헬퍼 - handlebars.registerHelper('formatDate', function(date: Date | string, format?: string) { - if (!date) return ''; - const d = new Date(date); - if (isNaN(d.getTime())) return ''; - - if (!format || format === 'date') { - return d.toISOString().split('T')[0]; - } - - if (format === 'datetime') { - return d.toLocaleString('ko-KR', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit' - }); - } - - return d.toLocaleDateString('ko-KR'); - }); - - // 숫자 포맷 헬퍼 - handlebars.registerHelper('formatNumber', function(number: number | string) { - if (typeof number === 'string') { - number = parseFloat(number); - } - if (isNaN(number)) return ''; - return number.toLocaleString('ko-KR'); - }); - - // 조건부 렌더링 헬퍼 - handlebars.registerHelper('ifEquals', function(this: unknown, arg1: unknown, arg2: unknown, options: { fn: (context: unknown) => string; inverse: (context: unknown) => string }) { - return (arg1 === arg2) ? options.fn(this) : options.inverse(this); - }); - - // 배열 길이 확인 헬퍼 - handlebars.registerHelper('ifArrayLength', function(this: unknown, array: unknown[], length: number, options: { fn: (context: unknown) => string; inverse: (context: unknown) => string }) { - return (Array.isArray(array) && array.length === length) ? options.fn(this) : options.inverse(this); - }); -} - -// Validation -function validateTemplate(content: string): TemplateValidationResult { - const errors: string[] = []; - const warnings: string[] = []; - - try { - // Handlebars 문법 검사 - handlebars.compile(content); - } catch (error) { - if (error instanceof Error) { - errors.push(`Handlebars 문법 오류: ${error.message}`); - } - } - - // 일반적인 문제 확인 - if (content.trim().length === 0) { - errors.push('템플릿 내용이 비어있습니다.'); - } - - // 위험한 패턴 확인 - if (content.includes('