dev #23
87
controller/admin/MailTemplatesController.js
Normal file
87
controller/admin/MailTemplatesController.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
const MailTemplateService = require('../../services/template/MailTemplateService');
|
||||||
|
|
||||||
|
class MailTemplatesController {
|
||||||
|
static _currentUserId(req) {
|
||||||
|
return req.user?.userId ?? req.user?.id ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async list(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.list(req.query || {});
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to list mail templates' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getById(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.getById(req.params.id);
|
||||||
|
if (!data) {
|
||||||
|
return res.status(404).json({ success: false, message: 'Mail template not found' });
|
||||||
|
}
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to load mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.create(req.body || {}, MailTemplatesController._currentUserId(req));
|
||||||
|
return res.status(201).json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to create mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async update(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.update(req.params.id, req.body || {}, MailTemplatesController._currentUserId(req));
|
||||||
|
if (!data) {
|
||||||
|
return res.status(404).json({ success: false, message: 'Mail template not found' });
|
||||||
|
}
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to update mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async activate(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.activate(req.params.id, MailTemplatesController._currentUserId(req));
|
||||||
|
if (!data) {
|
||||||
|
return res.status(404).json({ success: false, message: 'Mail template not found' });
|
||||||
|
}
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to activate mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async archive(req, res) {
|
||||||
|
try {
|
||||||
|
const data = await MailTemplateService.archive(req.params.id, MailTemplatesController._currentUserId(req));
|
||||||
|
if (!data) {
|
||||||
|
return res.status(404).json({ success: false, message: 'Mail template not found' });
|
||||||
|
}
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to archive mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async remove(req, res) {
|
||||||
|
try {
|
||||||
|
const deleted = await MailTemplateService.remove(req.params.id);
|
||||||
|
if (!deleted) {
|
||||||
|
return res.status(404).json({ success: false, message: 'Mail template not found' });
|
||||||
|
}
|
||||||
|
return res.json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(error?.status || 500).json({ success: false, message: error.message || 'Failed to delete mail template' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MailTemplatesController;
|
||||||
@ -451,6 +451,30 @@ const createDatabase = async () => {
|
|||||||
`);
|
`);
|
||||||
console.log('✅ Document templates table created/verified');
|
console.log('✅ Document templates table created/verified');
|
||||||
|
|
||||||
|
await connection.query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS mail_templates (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
template_type VARCHAR(100) NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
subject VARCHAR(255) NULL,
|
||||||
|
html_content LONGTEXT NOT NULL,
|
||||||
|
is_active TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
is_archived TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
archived_at TIMESTAMP NULL,
|
||||||
|
created_by INT NULL,
|
||||||
|
updated_by INT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT fk_mail_templates_created_by FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT fk_mail_templates_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||||
|
INDEX idx_mail_templates_type (template_type),
|
||||||
|
INDEX idx_mail_templates_active (is_active),
|
||||||
|
INDEX idx_mail_templates_archived (is_archived),
|
||||||
|
INDEX idx_mail_templates_type_active (template_type, is_active)
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
console.log('✅ Mail templates table created/verified');
|
||||||
|
|
||||||
// Ensure enum includes 'abo' on existing schemas
|
// Ensure enum includes 'abo' on existing schemas
|
||||||
try {
|
try {
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
@ -1806,6 +1830,10 @@ const createDatabase = async () => {
|
|||||||
await ensureIndex(connection, 'rate_limit', 'idx_rate_limit_rate_key', 'rate_key');
|
await ensureIndex(connection, 'rate_limit', 'idx_rate_limit_rate_key', 'rate_key');
|
||||||
await ensureIndex(connection, 'document_templates', 'idx_document_templates_user_type', 'user_type');
|
await ensureIndex(connection, 'document_templates', 'idx_document_templates_user_type', 'user_type');
|
||||||
await ensureIndex(connection, 'document_templates', 'idx_document_templates_state_user_type', 'state, user_type');
|
await ensureIndex(connection, 'document_templates', 'idx_document_templates_state_user_type', 'state, user_type');
|
||||||
|
await ensureIndex(connection, 'mail_templates', 'idx_mail_templates_type', 'template_type');
|
||||||
|
await ensureIndex(connection, 'mail_templates', 'idx_mail_templates_active', 'is_active');
|
||||||
|
await ensureIndex(connection, 'mail_templates', 'idx_mail_templates_archived', 'is_archived');
|
||||||
|
await ensureIndex(connection, 'mail_templates', 'idx_mail_templates_type_active', 'template_type, is_active');
|
||||||
await ensureIndex(connection, 'company_stamps', 'idx_company_stamps_company', 'company_id');
|
await ensureIndex(connection, 'company_stamps', 'idx_company_stamps_company', 'company_id');
|
||||||
await ensureIndex(connection, 'company_stamps', 'idx_company_stamps_active', 'is_active');
|
await ensureIndex(connection, 'company_stamps', 'idx_company_stamps_active', 'is_active');
|
||||||
console.log('🚀 Performance indexes created/verified');
|
console.log('🚀 Performance indexes created/verified');
|
||||||
|
|||||||
192
repositories/template/MailTemplateRepository.js
Normal file
192
repositories/template/MailTemplateRepository.js
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
const db = require('../../database/database');
|
||||||
|
|
||||||
|
class MailTemplateRepository {
|
||||||
|
_mapRow(row) {
|
||||||
|
if (!row) return null;
|
||||||
|
return {
|
||||||
|
id: Number(row.id),
|
||||||
|
template_type: row.template_type,
|
||||||
|
name: row.name,
|
||||||
|
subject: row.subject,
|
||||||
|
html_content: row.html_content,
|
||||||
|
is_active: row.is_active === 1 || row.is_active === true,
|
||||||
|
is_archived: row.is_archived === 1 || row.is_archived === true,
|
||||||
|
archived_at: row.archived_at,
|
||||||
|
created_by: row.created_by,
|
||||||
|
updated_by: row.updated_by,
|
||||||
|
created_at: row.created_at,
|
||||||
|
updated_at: row.updated_at,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async list({ includeArchived = false, templateType } = {}) {
|
||||||
|
const where = [];
|
||||||
|
const params = [];
|
||||||
|
|
||||||
|
if (!includeArchived) {
|
||||||
|
where.push('is_archived = 0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateType) {
|
||||||
|
where.push('template_type = ?');
|
||||||
|
params.push(templateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
const whereClause = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
||||||
|
const [rows] = await db.query(
|
||||||
|
`SELECT *
|
||||||
|
FROM mail_templates
|
||||||
|
${whereClause}
|
||||||
|
ORDER BY template_type ASC, is_active DESC, updated_at DESC`,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
return (rows || []).map((row) => this._mapRow(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(id) {
|
||||||
|
const [rows] = await db.query(
|
||||||
|
`SELECT *
|
||||||
|
FROM mail_templates
|
||||||
|
WHERE id = ?
|
||||||
|
LIMIT 1`,
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
return this._mapRow(rows?.[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(payload) {
|
||||||
|
const [result] = await db.query(
|
||||||
|
`INSERT INTO mail_templates
|
||||||
|
(template_type, name, subject, html_content, is_active, is_archived, created_by, updated_by)
|
||||||
|
VALUES (?, ?, ?, ?, 0, 0, ?, ?)`,
|
||||||
|
[
|
||||||
|
payload.template_type,
|
||||||
|
payload.name,
|
||||||
|
payload.subject || null,
|
||||||
|
payload.html_content,
|
||||||
|
payload.userId || null,
|
||||||
|
payload.userId || null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.getById(result.insertId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id, payload) {
|
||||||
|
const fields = [];
|
||||||
|
const values = [];
|
||||||
|
|
||||||
|
if (payload.template_type !== undefined) {
|
||||||
|
fields.push('template_type = ?');
|
||||||
|
values.push(payload.template_type);
|
||||||
|
}
|
||||||
|
if (payload.name !== undefined) {
|
||||||
|
fields.push('name = ?');
|
||||||
|
values.push(payload.name);
|
||||||
|
}
|
||||||
|
if (payload.subject !== undefined) {
|
||||||
|
fields.push('subject = ?');
|
||||||
|
values.push(payload.subject || null);
|
||||||
|
}
|
||||||
|
if (payload.html_content !== undefined) {
|
||||||
|
fields.push('html_content = ?');
|
||||||
|
values.push(payload.html_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.push('updated_by = ?');
|
||||||
|
values.push(payload.userId || null);
|
||||||
|
|
||||||
|
if (!fields.length) return this.getById(id);
|
||||||
|
|
||||||
|
values.push(id);
|
||||||
|
const [result] = await db.query(
|
||||||
|
`UPDATE mail_templates
|
||||||
|
SET ${fields.join(', ')}, updated_at = NOW()
|
||||||
|
WHERE id = ?`,
|
||||||
|
values
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result?.affectedRows) return null;
|
||||||
|
return this.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async activate(id, userId) {
|
||||||
|
const conn = await db.getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await conn.beginTransaction();
|
||||||
|
|
||||||
|
const [targetRows] = await conn.query(
|
||||||
|
`SELECT id, template_type, is_archived
|
||||||
|
FROM mail_templates
|
||||||
|
WHERE id = ?
|
||||||
|
LIMIT 1
|
||||||
|
FOR UPDATE`,
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
|
||||||
|
const target = targetRows?.[0];
|
||||||
|
if (!target) {
|
||||||
|
await conn.rollback();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.is_archived === 1 || target.is_archived === true) {
|
||||||
|
const error = new Error('Archived templates cannot be activated');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
await conn.query(
|
||||||
|
`UPDATE mail_templates
|
||||||
|
SET is_active = 0, updated_by = ?, updated_at = NOW()
|
||||||
|
WHERE template_type = ?`,
|
||||||
|
[userId || null, target.template_type]
|
||||||
|
);
|
||||||
|
|
||||||
|
await conn.query(
|
||||||
|
`UPDATE mail_templates
|
||||||
|
SET is_active = 1,
|
||||||
|
is_archived = 0,
|
||||||
|
archived_at = NULL,
|
||||||
|
updated_by = ?,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = ?`,
|
||||||
|
[userId || null, id]
|
||||||
|
);
|
||||||
|
|
||||||
|
await conn.commit();
|
||||||
|
} catch (error) {
|
||||||
|
await conn.rollback();
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
conn.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async archive(id, userId) {
|
||||||
|
const [result] = await db.query(
|
||||||
|
`UPDATE mail_templates
|
||||||
|
SET is_archived = 1,
|
||||||
|
is_active = 0,
|
||||||
|
archived_at = NOW(),
|
||||||
|
updated_by = ?,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = ?`,
|
||||||
|
[userId || null, id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result?.affectedRows) return null;
|
||||||
|
return this.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id) {
|
||||||
|
const [result] = await db.query('DELETE FROM mail_templates WHERE id = ?', [id]);
|
||||||
|
return Number(result?.affectedRows || 0) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new MailTemplateRepository();
|
||||||
@ -11,6 +11,7 @@ const AffiliateController = require('../controller/affiliate/AffiliateController
|
|||||||
const NewsController = require('../controller/news/NewsController');
|
const NewsController = require('../controller/news/NewsController');
|
||||||
const PoolController = require('../controller/pool/PoolController');
|
const PoolController = require('../controller/pool/PoolController');
|
||||||
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
||||||
|
const MailTemplatesController = require('../controller/admin/MailTemplatesController');
|
||||||
|
|
||||||
// Helper middlewares for company-stamp
|
// Helper middlewares for company-stamp
|
||||||
function forceCompanyForAdmin(req, res, next) {
|
function forceCompanyForAdmin(req, res, next) {
|
||||||
@ -22,6 +23,7 @@ function forceCompanyForAdmin(req, res, next) {
|
|||||||
|
|
||||||
// DELETE /admin/user/:id (moved from routes/admin.js)
|
// DELETE /admin/user/:id (moved from routes/admin.js)
|
||||||
router.delete('/admin/user/:id', authMiddleware, adminOnly, AdminUserController.deleteUser);
|
router.delete('/admin/user/:id', authMiddleware, adminOnly, AdminUserController.deleteUser);
|
||||||
|
router.delete('/admin/mail-templates/:id', authMiddleware, adminOnly, MailTemplatesController.remove);
|
||||||
|
|
||||||
// DELETE /document-templates/:id (moved from routes/documentTemplates.js)
|
// DELETE /document-templates/:id (moved from routes/documentTemplates.js)
|
||||||
router.delete('/document-templates/:id', authMiddleware, DocumentTemplateController.deleteTemplate);
|
router.delete('/document-templates/:id', authMiddleware, DocumentTemplateController.deleteTemplate);
|
||||||
|
|||||||
@ -32,6 +32,7 @@ const DashboardPlatformsController = require('../controller/admin/DashboardPlatf
|
|||||||
const ShippingFeesController = require('../controller/admin/ShippingFeesController');
|
const ShippingFeesController = require('../controller/admin/ShippingFeesController');
|
||||||
const LoginController = require('../controller/login/LoginController');
|
const LoginController = require('../controller/login/LoginController');
|
||||||
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
||||||
|
const MailTemplatesController = require('../controller/admin/MailTemplatesController');
|
||||||
|
|
||||||
const AUTH_VALIDATE_ROUTE_PATH = '/auth/validate';
|
const AUTH_VALIDATE_ROUTE_PATH = '/auth/validate';
|
||||||
|
|
||||||
@ -68,6 +69,8 @@ router.get('/verify-password-reset', (req, res) => { /* Note: was moved from Pas
|
|||||||
// admin.js GETs
|
// admin.js GETs
|
||||||
router.get('/admin/user-stats', authMiddleware, adminOnly, AdminUserController.getUserStats);
|
router.get('/admin/user-stats', authMiddleware, adminOnly, AdminUserController.getUserStats);
|
||||||
router.get('/admin/user-list', authMiddleware, adminOnly, AdminUserController.getUserList);
|
router.get('/admin/user-list', authMiddleware, adminOnly, AdminUserController.getUserList);
|
||||||
|
router.get('/admin/mail-templates', authMiddleware, adminOnly, MailTemplatesController.list);
|
||||||
|
router.get('/admin/mail-templates/:id', authMiddleware, adminOnly, MailTemplatesController.getById);
|
||||||
router.get('/admin/verification-pending-users', authMiddleware, adminOnly, AdminUserController.getVerificationPendingUsers);
|
router.get('/admin/verification-pending-users', authMiddleware, adminOnly, AdminUserController.getVerificationPendingUsers);
|
||||||
router.get('/admin/unverified-users', authMiddleware, adminOnly, AdminUserController.getUnverifiedUsers);
|
router.get('/admin/unverified-users', authMiddleware, adminOnly, AdminUserController.getUnverifiedUsers);
|
||||||
router.get('/admin/user/:id/documents', authMiddleware, adminOnly, UserDocumentController.getAllDocumentsForUser);
|
router.get('/admin/user/:id/documents', authMiddleware, adminOnly, UserDocumentController.getAllDocumentsForUser);
|
||||||
|
|||||||
@ -15,6 +15,7 @@ const NewsController = require('../controller/news/NewsController');
|
|||||||
const AbonemmentController = require('../controller/abonemments/AbonemmentController');
|
const AbonemmentController = require('../controller/abonemments/AbonemmentController');
|
||||||
const InvoiceController = require('../controller/invoice/InvoiceController');
|
const InvoiceController = require('../controller/invoice/InvoiceController');
|
||||||
const DashboardPlatformsController = require('../controller/admin/DashboardPlatformsController');
|
const DashboardPlatformsController = require('../controller/admin/DashboardPlatformsController');
|
||||||
|
const MailTemplatesController = require('../controller/admin/MailTemplatesController');
|
||||||
|
|
||||||
const multer = require('multer');
|
const multer = require('multer');
|
||||||
const upload = multer({ storage: multer.memoryStorage() });
|
const upload = multer({ storage: multer.memoryStorage() });
|
||||||
@ -36,6 +37,9 @@ router.patch('/company-stamps/:id/activate', authMiddleware, adminOnly, forceCom
|
|||||||
// Admin user management PATCH routes
|
// Admin user management PATCH routes
|
||||||
router.patch('/admin/archive-user/:id', authMiddleware, adminOnly, AdminUserController.archiveUser);
|
router.patch('/admin/archive-user/:id', authMiddleware, adminOnly, AdminUserController.archiveUser);
|
||||||
router.patch('/admin/unarchive-user/:id', authMiddleware, adminOnly, AdminUserController.unarchiveUser);
|
router.patch('/admin/unarchive-user/:id', authMiddleware, adminOnly, AdminUserController.unarchiveUser);
|
||||||
|
router.patch('/admin/mail-templates/:id', authMiddleware, adminOnly, MailTemplatesController.update);
|
||||||
|
router.patch('/admin/mail-templates/:id/activate', authMiddleware, adminOnly, MailTemplatesController.activate);
|
||||||
|
router.patch('/admin/mail-templates/:id/archive', authMiddleware, adminOnly, MailTemplatesController.archive);
|
||||||
router.patch('/admin/update-verification/:id', authMiddleware, adminOnly, AdminUserController.updateUserVerification);
|
router.patch('/admin/update-verification/:id', authMiddleware, adminOnly, AdminUserController.updateUserVerification);
|
||||||
router.patch('/admin/update-user-profile/:id', authMiddleware, adminOnly, AdminUserController.updateUserProfile);
|
router.patch('/admin/update-user-profile/:id', authMiddleware, adminOnly, AdminUserController.updateUserProfile);
|
||||||
router.patch('/admin/update-user-status/:id', authMiddleware, adminOnly, AdminUserController.updateUserStatus);
|
router.patch('/admin/update-user-status/:id', authMiddleware, adminOnly, AdminUserController.updateUserStatus);
|
||||||
|
|||||||
@ -33,6 +33,7 @@ const InvoiceController = require('../controller/invoice/InvoiceController'); //
|
|||||||
const DevManagementController = require('../controller/dev/DevManagementController');
|
const DevManagementController = require('../controller/dev/DevManagementController');
|
||||||
const DashboardPlatformsController = require('../controller/admin/DashboardPlatformsController');
|
const DashboardPlatformsController = require('../controller/admin/DashboardPlatformsController');
|
||||||
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
const I18nPreferencesController = require('../controller/admin/I18nPreferencesController');
|
||||||
|
const MailTemplatesController = require('../controller/admin/MailTemplatesController');
|
||||||
|
|
||||||
const multer = require('multer');
|
const multer = require('multer');
|
||||||
const upload = multer({ storage: multer.memoryStorage() });
|
const upload = multer({ storage: multer.memoryStorage() });
|
||||||
@ -83,6 +84,7 @@ router.post('/profile/company/complete', authMiddleware, CompanyProfileControlle
|
|||||||
|
|
||||||
// Admin POSTs (moved from routes/admin.js)
|
// Admin POSTs (moved from routes/admin.js)
|
||||||
router.post('/admin/verify-user/:id', authMiddleware, adminOnly, AdminUserController.verifyUser);
|
router.post('/admin/verify-user/:id', authMiddleware, adminOnly, AdminUserController.verifyUser);
|
||||||
|
router.post('/admin/mail-templates', authMiddleware, adminOnly, MailTemplatesController.create);
|
||||||
router.post('/admin/i18n/preferences', authMiddleware, adminOnly, I18nPreferencesController.post);
|
router.post('/admin/i18n/preferences', authMiddleware, adminOnly, I18nPreferencesController.post);
|
||||||
router.post('/i18n/preferences', authMiddleware, adminOnly, I18nPreferencesController.post);
|
router.post('/i18n/preferences', authMiddleware, adminOnly, I18nPreferencesController.post);
|
||||||
router.post('/i18n/translations', authMiddleware, adminOnly, I18nPreferencesController.upsertTranslations);
|
router.post('/i18n/translations', authMiddleware, adminOnly, I18nPreferencesController.upsertTranslations);
|
||||||
|
|||||||
122
services/template/MailTemplateService.js
Normal file
122
services/template/MailTemplateService.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
const MailTemplateRepository = require('../../repositories/template/MailTemplateRepository');
|
||||||
|
|
||||||
|
class MailTemplateService {
|
||||||
|
_requiredString(value, fieldName) {
|
||||||
|
const parsed = String(value == null ? '' : value).trim();
|
||||||
|
if (!parsed) {
|
||||||
|
const error = new Error(`${fieldName} is required`);
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
_optionalString(value) {
|
||||||
|
if (value === undefined || value === null) return null;
|
||||||
|
const parsed = String(value).trim();
|
||||||
|
return parsed || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_toBool(value, fallback = false) {
|
||||||
|
if (value === undefined || value === null) return fallback;
|
||||||
|
if (typeof value === 'boolean') return value;
|
||||||
|
const normalized = String(value).trim().toLowerCase();
|
||||||
|
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
||||||
|
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(query = {}) {
|
||||||
|
return MailTemplateRepository.list({
|
||||||
|
includeArchived: this._toBool(query.includeArchived, false),
|
||||||
|
templateType: this._optionalString(query.templateType),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(id) {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isFinite(numericId) || numericId <= 0) {
|
||||||
|
const error = new Error('Invalid id');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MailTemplateRepository.getById(numericId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(payload = {}, userId = null) {
|
||||||
|
const template_type = this._requiredString(payload.template_type, 'template_type');
|
||||||
|
const name = this._requiredString(payload.name, 'name');
|
||||||
|
const html_content = this._requiredString(payload.html_content, 'html_content');
|
||||||
|
|
||||||
|
return MailTemplateRepository.create({
|
||||||
|
template_type,
|
||||||
|
name,
|
||||||
|
subject: this._optionalString(payload.subject),
|
||||||
|
html_content,
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id, payload = {}, userId = null) {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isFinite(numericId) || numericId <= 0) {
|
||||||
|
const error = new Error('Invalid id');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePayload = {};
|
||||||
|
|
||||||
|
if (Object.prototype.hasOwnProperty.call(payload, 'template_type')) {
|
||||||
|
updatePayload.template_type = this._requiredString(payload.template_type, 'template_type');
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(payload, 'name')) {
|
||||||
|
updatePayload.name = this._requiredString(payload.name, 'name');
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(payload, 'subject')) {
|
||||||
|
updatePayload.subject = this._optionalString(payload.subject);
|
||||||
|
}
|
||||||
|
if (Object.prototype.hasOwnProperty.call(payload, 'html_content')) {
|
||||||
|
updatePayload.html_content = this._requiredString(payload.html_content, 'html_content');
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePayload.userId = userId;
|
||||||
|
return MailTemplateRepository.update(numericId, updatePayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
async activate(id, userId = null) {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isFinite(numericId) || numericId <= 0) {
|
||||||
|
const error = new Error('Invalid id');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MailTemplateRepository.activate(numericId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async archive(id, userId = null) {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isFinite(numericId) || numericId <= 0) {
|
||||||
|
const error = new Error('Invalid id');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MailTemplateRepository.archive(numericId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id) {
|
||||||
|
const numericId = Number(id);
|
||||||
|
if (!Number.isFinite(numericId) || numericId <= 0) {
|
||||||
|
const error = new Error('Invalid id');
|
||||||
|
error.status = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MailTemplateRepository.delete(numericId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new MailTemplateService();
|
||||||
Loading…
Reference in New Issue
Block a user