Add email notifications and sync dashboard

This commit is contained in:
Ruslan Bakiev
2026-04-07 10:25:28 +07:00
parent 386f6fa9fe
commit 92592e2baa
4 changed files with 299 additions and 37 deletions

View File

@@ -55,6 +55,45 @@ function getTransporter() {
return cachedTransporter;
}
function escapeHtml(value) {
return String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;');
}
function normalizeBody(body) {
if (Array.isArray(body)) {
return body
.map((line) => String(line ?? '').trim())
.filter(Boolean);
}
const text = String(body ?? '').trim();
return text ? [text] : [];
}
function buildNotificationEmailText(body, buttonText, buttonUrl) {
const lines = normalizeBody(body);
if (buttonUrl) {
lines.push(`${buttonText || 'Открыть'}: ${buttonUrl}`);
}
return lines.join('\n');
}
function buildNotificationEmailHtml(body, buttonText, buttonUrl) {
const paragraphs = normalizeBody(body)
.map((line) => `<p>${escapeHtml(line)}</p>`)
.join('');
if (!buttonUrl) {
return paragraphs;
}
return `${paragraphs}<p><a href="${escapeHtml(buttonUrl)}" style="display:inline-block;padding:12px 18px;border-radius:999px;background:#123824;color:#ffffff;text-decoration:none;font-weight:700;">${escapeHtml(buttonText || 'Открыть')}</a></p>`;
}
export async function sendLoginCodeEmail({ to, code, expiresAt }) {
const { from } = getSmtpConfig();
const transporter = getTransporter();
@@ -68,3 +107,16 @@ export async function sendLoginCodeEmail({ to, code, expiresAt }) {
html: template.html,
});
}
export async function sendNotificationEmail({ to, subject, body, buttonText = null, buttonUrl = null }) {
const { from } = getSmtpConfig();
const transporter = getTransporter();
await transporter.sendMail({
from,
to,
subject,
text: buildNotificationEmailText(body, buttonText, buttonUrl),
html: buildNotificationEmailHtml(body, buttonText, buttonUrl),
});
}