const express = require('express');
const Pushover = require('pushover-notifications');
const fs = require('node:fs');
const path = require('node:path');
const nodemailer = require('nodemailer');
const mustacheExpress = require('mustache-express');
const mustache = require('mustache');
const emailFrom = process.env.MAIL_FROM;
const emailSubject = process.env.MAIL_SUBJECT;
const notify_templates = getNotifyTemplates();
console.log("Listening for: " + Array.from(notify_templates.keys()).join(","));
const pushover = new Pushover(
{
user: process.env.PUSHOVER_USER,
token: process.env.PUSHOVER_TOKEN,
}
);
const testEmailData = {username:"Test User"};
function renderTemplateManual(template, data)
{
return mustache.render(fs.readFileSync(`views/${template}.html`, {'encoding':'utf8'}), data)
}
async function sendEmail(from, to, subject, html)
{
let transporter = nodemailer.createTransport({
host: process.env.MAIL_HOST,
port: 587, // Common port for secure SMTP (TLS)
secure: false, // Use 'true' if using port 465 (SSL), 'false' for other ports like 587 (TLS)
requireTLS: true,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
//await transporter.verify();
await transporter.sendMail({from, to, subject, html});
console.log(`Email sent to ${to}`);
}
const app = express();
// Register '.mustache' extension with The Mustache Express
app.engine('html', mustacheExpress());
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
app.use(express.json());
app.get('/email.html', (req, res) => res.send(renderTemplateManual('email', testEmailData))); // res.render('email', testEmailData));
app.get('/email_test', async (req, res) =>
{
await sendEmail(emailFrom, req.query.to, emailSubject, renderTemplateManual('email', testEmailData));
res.send('sent');
});
app.post('/', async (req, res, next) =>
{
console.log(req.body);
if ('event' in req.body)
{
if (notify_templates.has(req.body.event))
{
const template_output = JSON.parse(mustache.render(notify_templates.get(req.body.event), {
...req.body,
user: `${req.body.username} (${req.body.email})`
}));
if ('title' in template_output && 'message' in template_output)
{
pushover.send({
title: template_output.title,
message: template_output.message
});
}
if (req.body.event == 'user_joined')
{
try
{
await sendEmail(emailFrom, req.body.email, emailSubject, renderTemplateManual('email', req.body));
}
catch (err)
{
next(err);
}
}
}
}
res.end();
})
app.use((_, res) => res.status(404).end());
app.listen(80);
function getNotifyTemplates()
{
const templates = new Map();
const templatesStat = fs.statSync("templates", {throwIfNoEntry: false});
if (!templatesStat) fs.mkdirSync("templates");
if (fs.readdirSync("templates").length == 0)
{
for (let filename of fs.readdirSync("default_templates", {encoding:'utf8'}))
{
fs.copyFileSync(path.join("default_templates", filename), path.join("templates", filename));
}
}
for (let filename of fs.readdirSync("templates", {encoding:'utf8'}))
{
const is_comment = l => l.trim().startsWith("//");
if (path.extname(filename) != '.json') continue;
let lines = fs.readFileSync(path.join("templates", filename), {'encoding':'utf8'}).split(/[\r\n]/);
if (lines.some(l => is_comment(l) && l.indexOf(":ignore") != -1)) continue;
lines = lines.filter(l => !is_comment(l));
templates.set(path.parse(filename).name, lines.join("\n"));
}
return templates;
}