메일 관리 작업 저장용 커밋
This commit is contained in:
201
backend-node/src/controllers/mailAccountFileController.ts
Normal file
201
backend-node/src/controllers/mailAccountFileController.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { mailAccountFileService } from '../services/mailAccountFileService';
|
||||
|
||||
export class MailAccountFileController {
|
||||
async getAllAccounts(req: Request, res: Response) {
|
||||
try {
|
||||
const accounts = await mailAccountFileService.getAllAccounts();
|
||||
|
||||
// 비밀번호는 반환하지 않음
|
||||
const safeAccounts = accounts.map(({ smtpPassword, ...account }) => account);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: safeAccounts,
|
||||
total: safeAccounts.length,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '계정 조회 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getAccountById(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const account = await mailAccountFileService.getAccountById(id);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '계정을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 비밀번호는 마스킹 처리
|
||||
const { smtpPassword, ...safeAccount } = account;
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: {
|
||||
...safeAccount,
|
||||
smtpPassword: '••••••••', // 마스킹
|
||||
},
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '계정 조회 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async createAccount(req: Request, res: Response) {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
email,
|
||||
smtpHost,
|
||||
smtpPort,
|
||||
smtpSecure,
|
||||
smtpUsername,
|
||||
smtpPassword,
|
||||
dailyLimit,
|
||||
status,
|
||||
} = req.body;
|
||||
|
||||
if (!name || !email || !smtpHost || !smtpPort || !smtpUsername || !smtpPassword) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '필수 필드가 누락되었습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 이메일 중복 확인
|
||||
const existingAccount = await mailAccountFileService.getAccountByEmail(email);
|
||||
if (existingAccount) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '이미 등록된 이메일입니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const account = await mailAccountFileService.createAccount({
|
||||
name,
|
||||
email,
|
||||
smtpHost,
|
||||
smtpPort,
|
||||
smtpSecure: smtpSecure || false,
|
||||
smtpUsername,
|
||||
smtpPassword,
|
||||
dailyLimit: dailyLimit || 1000,
|
||||
status: status || 'active',
|
||||
});
|
||||
|
||||
// 비밀번호 제외하고 반환
|
||||
const { smtpPassword: _, ...safeAccount } = account;
|
||||
|
||||
return res.status(201).json({
|
||||
success: true,
|
||||
data: safeAccount,
|
||||
message: '메일 계정이 생성되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '계정 생성 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async updateAccount(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updates = req.body;
|
||||
|
||||
const account = await mailAccountFileService.updateAccount(id, updates);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '계정을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 비밀번호 제외하고 반환
|
||||
const { smtpPassword: _, ...safeAccount } = account;
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: safeAccount,
|
||||
message: '계정이 수정되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '계정 수정 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async deleteAccount(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const success = await mailAccountFileService.deleteAccount(id);
|
||||
|
||||
if (!success) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '계정을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: '계정이 삭제되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '계정 삭제 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async testConnection(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// TODO: 실제 SMTP 연결 테스트 구현
|
||||
// const account = await mailAccountFileService.getAccountById(id);
|
||||
// nodemailer로 연결 테스트
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: '연결 테스트 성공 (미구현)',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '연결 테스트 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const mailAccountFileController = new MailAccountFileController();
|
||||
|
||||
213
backend-node/src/controllers/mailQueryController.ts
Normal file
213
backend-node/src/controllers/mailQueryController.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { mailQueryService, QueryParameter } from '../services/mailQueryService';
|
||||
|
||||
export class MailQueryController {
|
||||
// 쿼리에서 파라미터 감지
|
||||
async detectParameters(req: Request, res: Response) {
|
||||
try {
|
||||
const { sql } = req.body;
|
||||
|
||||
if (!sql) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'SQL 쿼리가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const parameters = mailQueryService.detectParameters(sql);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: parameters,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '파라미터 감지 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 쿼리 테스트 실행
|
||||
async testQuery(req: Request, res: Response) {
|
||||
try {
|
||||
const { sql, parameters } = req.body;
|
||||
|
||||
if (!sql) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'SQL 쿼리가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const result = await mailQueryService.testQuery(
|
||||
sql,
|
||||
parameters || []
|
||||
);
|
||||
|
||||
return res.json({
|
||||
success: result.success,
|
||||
data: result,
|
||||
message: result.success
|
||||
? '쿼리 테스트 성공'
|
||||
: '쿼리 테스트 실패',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '쿼리 테스트 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 쿼리 실행
|
||||
async executeQuery(req: Request, res: Response) {
|
||||
try {
|
||||
const { sql, parameters } = req.body;
|
||||
|
||||
if (!sql) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'SQL 쿼리가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const result = await mailQueryService.executeQuery(
|
||||
sql,
|
||||
parameters || []
|
||||
);
|
||||
|
||||
return res.json({
|
||||
success: result.success,
|
||||
data: result,
|
||||
message: result.success
|
||||
? '쿼리 실행 성공'
|
||||
: '쿼리 실행 실패',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '쿼리 실행 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 변수 추출
|
||||
async extractVariables(req: Request, res: Response) {
|
||||
try {
|
||||
const { template } = req.body;
|
||||
|
||||
if (!template) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '템플릿이 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const variables = mailQueryService.extractVariables(template);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: variables,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '변수 추출 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 변수 매핑 검증
|
||||
async validateMapping(req: Request, res: Response) {
|
||||
try {
|
||||
const { templateVariables, queryFields } = req.body;
|
||||
|
||||
if (!templateVariables || !queryFields) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '템플릿 변수와 쿼리 필드가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const validation = mailQueryService.validateVariableMapping(
|
||||
templateVariables,
|
||||
queryFields
|
||||
);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: validation,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '변수 매핑 검증 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 대량 메일 데이터 처리
|
||||
async processMailData(req: Request, res: Response) {
|
||||
try {
|
||||
const { templateHtml, templateSubject, sql, parameters } = req.body;
|
||||
|
||||
if (!templateHtml || !templateSubject || !sql) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '템플릿, 제목, SQL 쿼리가 모두 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 쿼리 실행
|
||||
const queryResult = await mailQueryService.executeQuery(
|
||||
sql,
|
||||
parameters || []
|
||||
);
|
||||
|
||||
if (!queryResult.success) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '쿼리 실행 실패',
|
||||
error: queryResult.error,
|
||||
});
|
||||
}
|
||||
|
||||
// 메일 데이터 처리
|
||||
const mailData = await mailQueryService.processMailData(
|
||||
templateHtml,
|
||||
templateSubject,
|
||||
queryResult
|
||||
);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: {
|
||||
totalRecipients: mailData.length,
|
||||
mailData: mailData.slice(0, 5), // 미리보기용 5개만
|
||||
},
|
||||
message: `${mailData.length}명의 수신자에게 발송 준비 완료`,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '메일 데이터 처리 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const mailQueryController = new MailQueryController();
|
||||
|
||||
96
backend-node/src/controllers/mailSendSimpleController.ts
Normal file
96
backend-node/src/controllers/mailSendSimpleController.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { mailSendSimpleService } from '../services/mailSendSimpleService';
|
||||
|
||||
export class MailSendSimpleController {
|
||||
/**
|
||||
* 메일 발송 (단건 또는 소규모)
|
||||
*/
|
||||
async sendMail(req: Request, res: Response) {
|
||||
try {
|
||||
const { accountId, templateId, to, subject, variables, customHtml } = req.body;
|
||||
|
||||
// 필수 파라미터 검증
|
||||
if (!accountId || !to || !Array.isArray(to) || to.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '계정 ID와 수신자 이메일이 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
if (!subject) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '메일 제목이 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 템플릿 또는 커스텀 HTML 중 하나는 있어야 함
|
||||
if (!templateId && !customHtml) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '템플릿 또는 메일 내용이 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 메일 발송
|
||||
const result = await mailSendSimpleService.sendMail({
|
||||
accountId,
|
||||
templateId,
|
||||
to,
|
||||
subject,
|
||||
variables,
|
||||
customHtml,
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
return res.json({
|
||||
success: true,
|
||||
data: result,
|
||||
message: '메일이 발송되었습니다.',
|
||||
});
|
||||
} else {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: result.error || '메일 발송 실패',
|
||||
});
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '메일 발송 중 오류가 발생했습니다.',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SMTP 연결 테스트
|
||||
*/
|
||||
async testConnection(req: Request, res: Response) {
|
||||
try {
|
||||
const { accountId } = req.body;
|
||||
|
||||
if (!accountId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '계정 ID가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const result = await mailSendSimpleService.testConnection(accountId);
|
||||
|
||||
return res.json(result);
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '연결 테스트 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const mailSendSimpleController = new MailSendSimpleController();
|
||||
|
||||
258
backend-node/src/controllers/mailTemplateFileController.ts
Normal file
258
backend-node/src/controllers/mailTemplateFileController.ts
Normal file
@@ -0,0 +1,258 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { mailTemplateFileService } from '../services/mailTemplateFileService';
|
||||
import { mailQueryService } from '../services/mailQueryService';
|
||||
|
||||
export class MailTemplateFileController {
|
||||
// 모든 템플릿 조회
|
||||
async getAllTemplates(req: Request, res: Response) {
|
||||
try {
|
||||
const { category, search } = req.query;
|
||||
|
||||
let templates;
|
||||
if (search) {
|
||||
templates = await mailTemplateFileService.searchTemplates(search as string);
|
||||
} else if (category) {
|
||||
templates = await mailTemplateFileService.getTemplatesByCategory(category as string);
|
||||
} else {
|
||||
templates = await mailTemplateFileService.getAllTemplates();
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: templates,
|
||||
total: templates.length,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '템플릿 조회 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 템플릿 조회
|
||||
async getTemplateById(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const template = await mailTemplateFileService.getTemplateById(id);
|
||||
|
||||
if (!template) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '템플릿을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: template,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '템플릿 조회 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 생성
|
||||
async createTemplate(req: Request, res: Response) {
|
||||
try {
|
||||
const { name, subject, components, queryConfig, recipientConfig, category } = req.body;
|
||||
|
||||
if (!name || !subject || !Array.isArray(components)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '템플릿 이름, 제목, 컴포넌트가 필요합니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const template = await mailTemplateFileService.createTemplate({
|
||||
name,
|
||||
subject,
|
||||
components,
|
||||
queryConfig,
|
||||
recipientConfig,
|
||||
category,
|
||||
});
|
||||
|
||||
return res.status(201).json({
|
||||
success: true,
|
||||
data: template,
|
||||
message: '템플릿이 생성되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '템플릿 생성 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 수정
|
||||
async updateTemplate(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updates = req.body;
|
||||
|
||||
const template = await mailTemplateFileService.updateTemplate(id, updates);
|
||||
|
||||
if (!template) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '템플릿을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: template,
|
||||
message: '템플릿이 수정되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '템플릿 수정 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 삭제
|
||||
async deleteTemplate(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const success = await mailTemplateFileService.deleteTemplate(id);
|
||||
|
||||
if (!success) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '템플릿을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: '템플릿이 삭제되었습니다.',
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '템플릿 삭제 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 미리보기 (HTML 렌더링)
|
||||
async previewTemplate(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { sampleData } = req.body;
|
||||
|
||||
const template = await mailTemplateFileService.getTemplateById(id);
|
||||
if (!template) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '템플릿을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// HTML 렌더링
|
||||
let html = mailTemplateFileService.renderTemplateToHtml(template.components);
|
||||
let subject = template.subject;
|
||||
|
||||
// 샘플 데이터가 있으면 변수 치환
|
||||
if (sampleData) {
|
||||
html = mailQueryService.replaceVariables(html, sampleData);
|
||||
subject = mailQueryService.replaceVariables(subject, sampleData);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: {
|
||||
subject,
|
||||
html,
|
||||
sampleData,
|
||||
},
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '미리보기 생성 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 템플릿 + 쿼리 통합 미리보기
|
||||
async previewWithQuery(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { queryId, parameters } = req.body;
|
||||
|
||||
const template = await mailTemplateFileService.getTemplateById(id);
|
||||
if (!template) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '템플릿을 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
// 쿼리 실행
|
||||
const query = template.queryConfig?.queries.find(q => q.id === queryId);
|
||||
if (!query) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '쿼리를 찾을 수 없습니다.',
|
||||
});
|
||||
}
|
||||
|
||||
const queryResult = await mailQueryService.executeQuery(query.sql, parameters || []);
|
||||
if (!queryResult.success || !queryResult.data || queryResult.data.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '쿼리 결과가 없습니다.',
|
||||
error: queryResult.error,
|
||||
});
|
||||
}
|
||||
|
||||
// 첫 번째 행으로 미리보기
|
||||
const sampleData = queryResult.data[0];
|
||||
let html = mailTemplateFileService.renderTemplateToHtml(template.components);
|
||||
let subject = template.subject;
|
||||
|
||||
html = mailQueryService.replaceVariables(html, sampleData);
|
||||
subject = mailQueryService.replaceVariables(subject, sampleData);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: {
|
||||
subject,
|
||||
html,
|
||||
sampleData,
|
||||
totalRecipients: queryResult.data.length,
|
||||
},
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as Error;
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '쿼리 미리보기 실패',
|
||||
error: err.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const mailTemplateFileController = new MailTemplateFileController();
|
||||
|
||||
Reference in New Issue
Block a user