Nya notifikations alternativ

This commit is contained in:
2026-06-16 21:37:11 +02:00
parent 8491fe1386
commit 125fddfb1b
8 changed files with 395 additions and 78 deletions
+130 -37
View File
@@ -1,69 +1,162 @@
const settings = require('./settings');
const db = require('./db');
const settings = require('./settings');
const db = require('./db');
const nodemailer = require('nodemailer');
/**
* Send a Gotify notification if enabled and configured.
* Errors are logged but never thrown — notifications are best-effort.
*/
async function notify(title, message) {
// ─── Channel senders ──────────────────────────────────────────────────────────
async function sendGotify(title, message) {
const { gotify } = settings.get();
if (!gotify.enabled || !gotify.url || !gotify.token) return;
const base = gotify.url.replace(/\/$/, '');
try {
const res = await fetch(`${base}/message?token=${encodeURIComponent(gotify.token)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title,
message,
priority: gotify.priority ?? 5,
}),
body: JSON.stringify({ title, message, priority: gotify.priority ?? 5 }),
});
if (!res.ok) {
const text = await res.text().catch(() => '');
console.error(`[notify] Gotify error ${res.status}: ${text}`);
}
if (!res.ok) console.error(`[notify] Gotify error ${res.status}: ${await res.text().catch(() => '')}`);
} catch (err) {
console.error('[notify] Failed to send Gotify notification:', err.message);
console.error('[notify] Gotify failed:', err.message);
}
}
// ─── Convenience helpers ─────────────────────────────────────────────────────
async function sendNtfy(title, message) {
const { ntfy } = settings.get();
if (!ntfy.enabled || !ntfy.url || !ntfy.topic) return;
const base = ntfy.url.replace(/\/$/, '');
const headers = {
'Content-Type': 'text/plain',
'Title': title,
'Priority': String(ntfy.priority ?? 3),
};
if (ntfy.token) headers['Authorization'] = `Bearer ${ntfy.token}`;
try {
const res = await fetch(`${base}/${encodeURIComponent(ntfy.topic)}`, {
method: 'POST',
headers,
body: message,
});
if (!res.ok) console.error(`[notify] ntfy error ${res.status}: ${await res.text().catch(() => '')}`);
} catch (err) {
console.error('[notify] ntfy failed:', err.message);
}
}
async function sendSmtp(title, message) {
const { smtp } = settings.get();
if (!smtp.enabled || !smtp.host || !smtp.to || !smtp.from) return;
try {
const transporter = nodemailer.createTransport({
host: smtp.host,
port: Number(smtp.port) || 587,
secure: smtp.secure === true || smtp.secure === 'true',
auth: smtp.username ? { user: smtp.username, pass: smtp.password } : undefined,
});
await transporter.sendMail({
from: smtp.from,
to: smtp.to,
subject: title,
text: message,
});
} catch (err) {
console.error('[notify] SMTP failed:', err.message);
}
}
async function sendWebhook(title, message) {
const { webhook } = settings.get();
if (!webhook.enabled || !webhook.url) return;
const body = JSON.stringify({ content: `**${title}**\n${message}` });
const headers = { 'Content-Type': 'application/json' };
if (webhook.secret) headers['X-Webhook-Secret'] = webhook.secret;
try {
const res = await fetch(webhook.url, { method: 'POST', headers, body });
if (!res.ok) console.error(`[notify] Webhook error ${res.status}: ${await res.text().catch(() => '')}`);
} catch (err) {
console.error('[notify] Webhook failed:', err.message);
}
}
// ─── Broadcast to all enabled channels ───────────────────────────────────────
async function notify(title, message) {
await Promise.all([
sendGotify(title, message),
sendNtfy(title, message),
sendSmtp(title, message),
sendWebhook(title, message),
]);
}
// ─── Exported senders for test routes ────────────────────────────────────────
async function testGotify(cfg) {
const base = cfg.url.replace(/\/$/, '');
const res = await fetch(`${base}/message?token=${encodeURIComponent(cfg.token)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: '🦥 Sloth Manager — Test', message: 'Gotify notifications are working correctly.', priority: cfg.priority ?? 5 }),
});
if (!res.ok) throw new Error(`Gotify returned ${res.status}: ${await res.text().catch(() => '')}`);
}
async function testNtfy(cfg) {
const base = cfg.url.replace(/\/$/, '');
const headers = { 'Content-Type': 'text/plain', Title: '🦥 Sloth Manager — Test', Priority: String(cfg.priority ?? 3) };
if (cfg.token) headers['Authorization'] = `Bearer ${cfg.token}`;
const res = await fetch(`${base}/${encodeURIComponent(cfg.topic)}`, { method: 'POST', headers, body: 'ntfy notifications are working correctly.' });
if (!res.ok) throw new Error(`ntfy returned ${res.status}: ${await res.text().catch(() => '')}`);
}
async function testSmtp(cfg) {
const transporter = nodemailer.createTransport({
host: cfg.host,
port: Number(cfg.port) || 587,
secure: cfg.secure === true || cfg.secure === 'true',
auth: cfg.username ? { user: cfg.username, pass: cfg.password } : undefined,
});
await transporter.verify();
await transporter.sendMail({
from: cfg.from,
to: cfg.to,
subject: '🦥 Sloth Manager — Test',
text: 'SMTP notifications are working correctly.',
});
}
async function testWebhook(cfg) {
const headers = { 'Content-Type': 'application/json' };
if (cfg.secret) headers['X-Webhook-Secret'] = cfg.secret;
const res = await fetch(cfg.url, {
method: 'POST',
headers,
body: JSON.stringify({ content: '**🦥 Sloth Manager — Test**\nWebhook notifications are working correctly.' }),
});
if (!res.ok) throw new Error(`Webhook returned ${res.status}: ${await res.text().catch(() => '')}`);
}
// ─── Event helpers ────────────────────────────────────────────────────────────
function eventEnabled(key) {
const { notifications } = settings.get();
return notifications?.[key] !== false;
return settings.get().notifications?.[key] !== false;
}
function recordAdded(provider, zoneId, record) {
if (!eventEnabled('dns_add')) return;
const zoneName = db.getZoneName(provider, zoneId);
return notify(
`DNS Record Added`,
`[${provider}] ${zoneName}\n+ ${record.type} ${record.name}${record.content}`,
);
return notify(`DNS Record Added`, `[${provider}] ${zoneName}\n+ ${record.type} ${record.name}${record.content}`);
}
function recordUpdated(provider, zoneId, oldRecord, newRecord) {
if (!eventEnabled('dns_update')) return;
const zoneName = db.getZoneName(provider, zoneId);
return notify(
`DNS Record Updated`,
`[${provider}] ${zoneName}\n${oldRecord.type} ${oldRecord.name}\n ${oldRecord.content}${newRecord.content}`,
);
return notify(`DNS Record Updated`, `[${provider}] ${zoneName}\n${oldRecord.type} ${oldRecord.name}\n ${oldRecord.content}${newRecord.content}`);
}
function recordDeleted(provider, zoneId, record) {
if (!eventEnabled('dns_delete')) return;
const zoneName = db.getZoneName(provider, zoneId);
return notify(
`DNS Record Deleted`,
`[${provider}] ${zoneName}\n ${record.type} ${record.name} ${record.content}`,
);
return notify(`DNS Record Deleted`, `[${provider}] ${zoneName}\n ${record.type} ${record.name} ${record.content}`);
}
module.exports = { notify, recordAdded, recordUpdated, recordDeleted };
module.exports = { notify, testGotify, testNtfy, testSmtp, testWebhook, recordAdded, recordUpdated, recordDeleted };