mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
162 lines
7.2 KiB
JavaScript
162 lines
7.2 KiB
JavaScript
'use strict';
|
|
|
|
const mdl_NotificationTemplate = require('../../models/notifications/notification_template.mdl');
|
|
const R = require('../../utils/response.util');
|
|
const logActivity = require('../../utils/logActivity.util');
|
|
|
|
const slugify = (str) =>
|
|
str.toLowerCase().trim().replace(/[^a-z0-9]+/g, '_').replace(/(^_|_$)/g, '');
|
|
|
|
// ─── GET /admin/notification-templates ─────────────────────────────────────────
|
|
|
|
exports.getNotificationTemplates = async (req, res) => {
|
|
try {
|
|
const templates = await mdl_NotificationTemplate.findAll({
|
|
order: [['notify_type', 'ASC'], ['type', 'ASC']],
|
|
});
|
|
return R.success(res, 'Announcement templates retrieved.', templates);
|
|
} catch (err) {
|
|
console.error('[ADMIN][GET NOTIFICATION TEMPLATES]', err);
|
|
return R.error(res, 'Could not retrieve announcement templates.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── GET /admin/notification-templates/:id ─────────────────────────────────────
|
|
|
|
exports.getNotificationTemplate = async (req, res) => {
|
|
try {
|
|
const template = await mdl_NotificationTemplate.findByPk(req.params.id);
|
|
if (!template) return R.error(res, 'Announcement template not found.', 404);
|
|
return R.success(res, 'Announcement template retrieved.', template);
|
|
} catch (err) {
|
|
console.error('[ADMIN][GET NOTIFICATION TEMPLATE]', err);
|
|
return R.error(res, 'Could not retrieve announcement template.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── POST /admin/notification-templates ────────────────────────────────────────
|
|
// Only creates custom (is_system: false) rows. System types still can't be
|
|
// added here — they need a code call site (services/notificationTemplate
|
|
// .service.js's renderNotification()) before a type means anything. Custom
|
|
// rows have no call site at all: they're reusable title/message presets an
|
|
// admin can load into the Announcements composer (see AddNotificationBroadcast
|
|
// .jsx), so `type` only exists to satisfy the unique key — nothing looks it up.
|
|
|
|
exports.createNotificationTemplate = async (req, res) => {
|
|
try {
|
|
const { label, title, message } = req.body;
|
|
if (!label?.trim()) return R.error(res, 'label is required.', 400);
|
|
if (!title?.trim()) return R.error(res, 'title is required.', 400);
|
|
if (!message?.trim()) return R.error(res, 'message cannot be empty.', 400);
|
|
|
|
const base = slugify(label) || 'template';
|
|
let type = `custom_${base}`;
|
|
let suffix = 1;
|
|
while (await mdl_NotificationTemplate.findOne({ where: { type } })) {
|
|
suffix += 1;
|
|
type = `custom_${base}_${suffix}`;
|
|
}
|
|
|
|
const template = await mdl_NotificationTemplate.create({
|
|
type,
|
|
notify_type: 'announcement',
|
|
scope: 'both',
|
|
label: label.trim(),
|
|
status: 'sent',
|
|
title: title.trim(),
|
|
message: message.trim(),
|
|
is_system: false,
|
|
});
|
|
|
|
logActivity(req.user?.user_id, 'create_notification_template', { entityType: 'notification_template', entityId: template.notification_template_id, details: { label: template.label } });
|
|
|
|
return R.success(res, 'Announcement template created.', template, 201);
|
|
} catch (err) {
|
|
console.error('[ADMIN][CREATE NOTIFICATION TEMPLATE]', err);
|
|
return R.error(res, 'Could not create announcement template.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── DELETE /admin/notification-templates/:id ──────────────────────────────────
|
|
// System templates stay protected — deleting one would break the code call
|
|
// site that references its type.
|
|
|
|
exports.deleteNotificationTemplate = async (req, res) => {
|
|
try {
|
|
const template = await mdl_NotificationTemplate.findByPk(req.params.id);
|
|
if (!template) return R.error(res, 'Announcement template not found.', 404);
|
|
if (template.is_system) return R.error(res, 'System templates cannot be deleted.', 400);
|
|
|
|
await template.destroy();
|
|
|
|
logActivity(req.user?.user_id, 'delete_notification_template', { entityType: 'notification_template', entityId: template.notification_template_id, details: { label: template.label } });
|
|
|
|
return R.success(res, 'Announcement template deleted.');
|
|
} catch (err) {
|
|
console.error('[ADMIN][DELETE NOTIFICATION TEMPLATE]', err);
|
|
return R.error(res, 'Could not delete announcement template.', 500);
|
|
}
|
|
};
|
|
|
|
// ─── PUT /admin/notification-templates/:id ─────────────────────────────────────
|
|
|
|
exports.updateNotificationTemplate = async (req, res) => {
|
|
try {
|
|
const template = await mdl_NotificationTemplate.findByPk(req.params.id);
|
|
if (!template) return R.error(res, 'Announcement template not found.', 404);
|
|
|
|
const { label, title, message, publish } = req.body;
|
|
|
|
if (title !== undefined && !title.trim()) return R.error(res, 'title cannot be empty.', 400);
|
|
if (message !== undefined && !message.trim()) return R.error(res, 'message cannot be empty.', 400);
|
|
|
|
// Custom templates are just reusable presets — nothing reads them at a
|
|
// fixed publish time, so there's no draft/publish workflow: title/message
|
|
// save straight to the live columns.
|
|
if (!template.is_system) {
|
|
await template.update({
|
|
label: label ?? template.label,
|
|
title: title ?? template.title,
|
|
message: message ?? template.message,
|
|
});
|
|
|
|
logActivity(req.user?.user_id, 'update_notification_template', { entityType: 'notification_template', entityId: template.notification_template_id, details: { custom: true } });
|
|
|
|
return R.success(res, 'Announcement template updated.', template);
|
|
}
|
|
|
|
// "Publish" writes title/message straight to the live columns
|
|
// renderNotification() reads and clears any pending draft. A plain save
|
|
// (no publish flag) writes into draft_title/draft_message instead, so
|
|
// real notifications keep using the last-published content until an
|
|
// admin comes back and explicitly publishes again.
|
|
const isPublishing = publish === true || publish === 'true';
|
|
const nextTitle = title ?? template.draft_title ?? template.title;
|
|
const nextMessage = message ?? template.draft_message ?? template.message;
|
|
|
|
await template.update({
|
|
label: label ?? template.label,
|
|
...(isPublishing
|
|
? {
|
|
status: 'sent',
|
|
title: nextTitle,
|
|
message: nextMessage,
|
|
draft_title: null,
|
|
draft_message: null,
|
|
last_sent_at: new Date(),
|
|
}
|
|
: {
|
|
draft_title: nextTitle,
|
|
draft_message: nextMessage,
|
|
}),
|
|
});
|
|
|
|
logActivity(req.user?.user_id, 'update_notification_template', { entityType: 'notification_template', entityId: template.notification_template_id, details: { type: template.type, published: isPublishing } });
|
|
|
|
return R.success(res, 'Announcement template updated.', template);
|
|
} catch (err) {
|
|
console.error('[ADMIN][UPDATE NOTIFICATION TEMPLATE]', err);
|
|
return R.error(res, 'Could not update announcement template.', 500);
|
|
}
|
|
};
|