2025-10-02 18:22:58 +09:00
|
|
|
import { Request, Response } from 'express';
|
|
|
|
|
import { mailSentHistoryService } from '../services/mailSentHistoryService';
|
|
|
|
|
|
|
|
|
|
export class MailSentHistoryController {
|
|
|
|
|
/**
|
|
|
|
|
* 발송 이력 목록 조회
|
|
|
|
|
*/
|
|
|
|
|
async getList(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const query = {
|
|
|
|
|
page: req.query.page ? parseInt(req.query.page as string) : undefined,
|
|
|
|
|
limit: req.query.limit ? parseInt(req.query.limit as string) : undefined,
|
|
|
|
|
searchTerm: req.query.searchTerm as string | undefined,
|
2025-10-22 16:06:04 +09:00
|
|
|
status: req.query.status as 'success' | 'failed' | 'draft' | 'all' | undefined,
|
2025-10-02 18:22:58 +09:00
|
|
|
accountId: req.query.accountId as string | undefined,
|
|
|
|
|
startDate: req.query.startDate as string | undefined,
|
|
|
|
|
endDate: req.query.endDate as string | undefined,
|
2025-10-22 16:06:04 +09:00
|
|
|
sortBy: req.query.sortBy as 'sentAt' | 'subject' | 'updatedAt' | undefined,
|
2025-10-02 18:22:58 +09:00
|
|
|
sortOrder: req.query.sortOrder as 'asc' | 'desc' | undefined,
|
2025-10-22 16:06:04 +09:00
|
|
|
includeDeleted: req.query.includeDeleted === 'true',
|
|
|
|
|
onlyDeleted: req.query.onlyDeleted === 'true',
|
2025-10-02 18:22:58 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const result = await mailSentHistoryService.getSentMailList(query);
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: result,
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('발송 이력 목록 조회 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력 조회 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 특정 발송 이력 상세 조회
|
|
|
|
|
*/
|
|
|
|
|
async getById(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력 ID가 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const history = await mailSentHistoryService.getSentMailById(id);
|
|
|
|
|
|
|
|
|
|
if (!history) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력을 찾을 수 없습니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: history,
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('발송 이력 조회 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력 조회 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 발송 이력 삭제
|
|
|
|
|
*/
|
|
|
|
|
async deleteById(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력 ID가 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const success = await mailSentHistoryService.deleteSentMail(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;
|
|
|
|
|
console.error('발송 이력 삭제 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '발송 이력 삭제 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-22 16:06:04 +09:00
|
|
|
/**
|
|
|
|
|
* 임시 저장 (Draft)
|
|
|
|
|
*/
|
|
|
|
|
async saveDraft(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const draft = await mailSentHistoryService.saveDraft(req.body);
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: draft,
|
|
|
|
|
message: '임시 저장되었습니다.',
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('임시 저장 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '임시 저장 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 임시 저장 업데이트
|
|
|
|
|
*/
|
|
|
|
|
async updateDraft(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '임시 저장 ID가 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updated = await mailSentHistoryService.updateDraft(id, req.body);
|
|
|
|
|
|
|
|
|
|
if (!updated) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '임시 저장을 찾을 수 없습니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: updated,
|
|
|
|
|
message: '임시 저장이 업데이트되었습니다.',
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('임시 저장 업데이트 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '임시 저장 업데이트 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메일 복구
|
|
|
|
|
*/
|
|
|
|
|
async restoreMail(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '메일 ID가 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const success = await mailSentHistoryService.restoreMail(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;
|
|
|
|
|
console.error('메일 복구 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '메일 복구 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 메일 영구 삭제
|
|
|
|
|
*/
|
|
|
|
|
async permanentlyDelete(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!id) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '메일 ID가 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const success = await mailSentHistoryService.permanentlyDeleteMail(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;
|
|
|
|
|
console.error('메일 영구 삭제 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '메일 영구 삭제 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-02 18:22:58 +09:00
|
|
|
/**
|
|
|
|
|
* 통계 조회
|
|
|
|
|
*/
|
|
|
|
|
async getStatistics(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const accountId = req.query.accountId as string | undefined;
|
|
|
|
|
const stats = await mailSentHistoryService.getStatistics(accountId);
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
data: stats,
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('통계 조회 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '통계 조회 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-22 16:06:04 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 일괄 삭제
|
|
|
|
|
*/
|
|
|
|
|
async bulkDelete(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { ids } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '삭제할 메일 ID 목록이 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const results = await Promise.allSettled(
|
|
|
|
|
ids.map((id: string) => mailSentHistoryService.deleteSentMail(id))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const successCount = results.filter((r) => r.status === 'fulfilled' && r.value).length;
|
|
|
|
|
const failCount = results.length - successCount;
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: `${successCount}개 메일 삭제 완료 (실패: ${failCount}개)`,
|
|
|
|
|
data: { successCount, failCount },
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('일괄 삭제 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '일괄 삭제 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 일괄 영구 삭제
|
|
|
|
|
*/
|
|
|
|
|
async bulkPermanentDelete(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { ids } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '영구 삭제할 메일 ID 목록이 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const results = await Promise.allSettled(
|
|
|
|
|
ids.map((id: string) => mailSentHistoryService.permanentlyDeleteMail(id))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const successCount = results.filter((r) => r.status === 'fulfilled' && r.value).length;
|
|
|
|
|
const failCount = results.length - successCount;
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: `${successCount}개 메일 영구 삭제 완료 (실패: ${failCount}개)`,
|
|
|
|
|
data: { successCount, failCount },
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('일괄 영구 삭제 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '일괄 영구 삭제 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 일괄 복구
|
|
|
|
|
*/
|
|
|
|
|
async bulkRestore(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { ids } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '복구할 메일 ID 목록이 필요합니다.',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const results = await Promise.allSettled(
|
|
|
|
|
ids.map((id: string) => mailSentHistoryService.restoreMail(id))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const successCount = results.filter((r) => r.status === 'fulfilled' && r.value).length;
|
|
|
|
|
const failCount = results.length - successCount;
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
message: `${successCount}개 메일 복구 완료 (실패: ${failCount}개)`,
|
|
|
|
|
data: { successCount, failCount },
|
|
|
|
|
});
|
|
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('일괄 복구 실패:', err);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: '일괄 복구 중 오류가 발생했습니다.',
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-02 18:22:58 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const mailSentHistoryController = new MailSentHistoryController();
|
|
|
|
|
|