Updated A LOT
This commit is contained in:
118
server/services/notifications.js
Normal file
118
server/services/notifications.js
Normal file
@@ -0,0 +1,118 @@
|
||||
const nodemailer = require('nodemailer');
|
||||
const { all, audit, now, run } = require('../db');
|
||||
|
||||
function readSettings() {
|
||||
const rows = all('SELECT key, value FROM app_settings');
|
||||
return Object.fromEntries(rows.map((row) => [row.key, row.value]));
|
||||
}
|
||||
|
||||
// Raw config (includes password) — for sending mail only.
|
||||
function getConfig() {
|
||||
const s = readSettings();
|
||||
return {
|
||||
host: s.smtp_host || '',
|
||||
port: Number(s.smtp_port || 587),
|
||||
secure: s.smtp_secure === 'true',
|
||||
user: s.smtp_user || '',
|
||||
password: s.smtp_password || '',
|
||||
from: s.smtp_from || s.smtp_user || '',
|
||||
enabled: s.alerts_enabled === 'true',
|
||||
leadDays: Number(s.alerts_lead_days || 30),
|
||||
recipients: String(s.alerts_recipients || '').split(',').map((x) => x.trim()).filter(Boolean),
|
||||
webhookEnabled: s.webhook_enabled === 'true',
|
||||
webhookUrl: s.webhook_url || '',
|
||||
webhookSecret: s.webhook_secret || ''
|
||||
};
|
||||
}
|
||||
|
||||
// Safe config for the API/UI — password is never returned, only whether it is set.
|
||||
function publicConfig() {
|
||||
const c = getConfig();
|
||||
return {
|
||||
smtp_host: c.host,
|
||||
smtp_port: c.port,
|
||||
smtp_secure: c.secure,
|
||||
smtp_user: c.user,
|
||||
smtp_from: c.from,
|
||||
smtp_password_set: Boolean(c.password),
|
||||
alerts_enabled: c.enabled,
|
||||
alerts_lead_days: c.leadDays,
|
||||
alerts_recipients: c.recipients.join(', '),
|
||||
configured: Boolean(c.host),
|
||||
webhook_enabled: c.webhookEnabled,
|
||||
webhook_url: c.webhookUrl,
|
||||
webhook_secret_set: Boolean(c.webhookSecret),
|
||||
webhook_configured: Boolean(c.webhookUrl)
|
||||
};
|
||||
}
|
||||
|
||||
function setValue(key, value) {
|
||||
run(
|
||||
'INSERT INTO app_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at',
|
||||
[key, String(value), now()]
|
||||
);
|
||||
}
|
||||
|
||||
function saveConfig(body, userId) {
|
||||
if (body.smtp_host !== undefined) setValue('smtp_host', body.smtp_host || '');
|
||||
if (body.smtp_port !== undefined) setValue('smtp_port', Number(body.smtp_port) || 587);
|
||||
if (body.smtp_secure !== undefined) setValue('smtp_secure', body.smtp_secure ? 'true' : 'false');
|
||||
if (body.smtp_user !== undefined) setValue('smtp_user', body.smtp_user || '');
|
||||
if (body.smtp_from !== undefined) setValue('smtp_from', body.smtp_from || '');
|
||||
if (body.smtp_password) setValue('smtp_password', body.smtp_password); // only overwrite when a new value is supplied
|
||||
if (body.alerts_enabled !== undefined) setValue('alerts_enabled', body.alerts_enabled ? 'true' : 'false');
|
||||
if (body.alerts_lead_days !== undefined) setValue('alerts_lead_days', Number(body.alerts_lead_days) || 30);
|
||||
if (body.alerts_recipients !== undefined) setValue('alerts_recipients', body.alerts_recipients || '');
|
||||
if (body.webhook_enabled !== undefined) setValue('webhook_enabled', body.webhook_enabled ? 'true' : 'false');
|
||||
if (body.webhook_url !== undefined) setValue('webhook_url', body.webhook_url || '');
|
||||
if (body.webhook_secret_clear) setValue('webhook_secret', '');
|
||||
else if (body.webhook_secret) setValue('webhook_secret', body.webhook_secret); // only overwrite when a new value is supplied
|
||||
audit(userId, 'update', 'notification_settings', 'smtp', null, {
|
||||
...body,
|
||||
smtp_password: body.smtp_password ? '[set]' : undefined,
|
||||
webhook_secret: body.webhook_secret ? '[set]' : undefined
|
||||
});
|
||||
return publicConfig();
|
||||
}
|
||||
|
||||
function getTransport() {
|
||||
const c = getConfig();
|
||||
if (!c.host) {
|
||||
throw Object.assign(new Error('SMTP host is not configured'), { status: 400 });
|
||||
}
|
||||
return nodemailer.createTransport({
|
||||
host: c.host,
|
||||
port: c.port,
|
||||
secure: c.secure,
|
||||
auth: c.user ? { user: c.user, pass: c.password } : undefined
|
||||
});
|
||||
}
|
||||
|
||||
async function sendMail({ to, subject, html, text }) {
|
||||
const c = getConfig();
|
||||
const recipients = to ? (Array.isArray(to) ? to : [to]) : c.recipients;
|
||||
if (!recipients.length) {
|
||||
throw Object.assign(new Error('No recipients are configured'), { status: 400 });
|
||||
}
|
||||
const transport = getTransport();
|
||||
return transport.sendMail({
|
||||
from: c.from || c.user,
|
||||
to: recipients.join(', '),
|
||||
subject,
|
||||
html,
|
||||
text
|
||||
});
|
||||
}
|
||||
|
||||
async function sendTestEmail(to, userId) {
|
||||
const info = await sendMail({
|
||||
to: to ? [to] : null,
|
||||
subject: 'MixedAssets test email',
|
||||
html: '<p>Your MixedAssets SMTP settings are working. This is a test message.</p>',
|
||||
text: 'Your MixedAssets SMTP settings are working. This is a test message.'
|
||||
});
|
||||
audit(userId, 'send', 'test_email', null, null, { to });
|
||||
return { messageId: info.messageId, accepted: info.accepted };
|
||||
}
|
||||
|
||||
module.exports = { getConfig, publicConfig, saveConfig, sendMail, sendTestEmail };
|
||||
Reference in New Issue
Block a user