This is the template project that's checked out and configured when you run the bando-up command from ljsthw-bandolier. This is where the code really lives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bandolier-template/queues/mail.js

172 lines
5.1 KiB

import logging from '../lib/logging.js';
import { company } from '../emails/config.js';
import { send_email, load_templates, debug_templates } from '../lib/email.js';
import { User, Payment, Product, RESET_CODE_SIZE } from "../lib/models.js";
import assert from "assert";
import differenceInHours from 'date-fns/differenceInHours/index.js';
const RESET_HOURS_MAX = 10;
const log = logging.create("/queues/mail.js");
const generic_emailer = async (name, user, mail_form, t_vars, send_vars) => {
try {
const text = mail_form.txt(t_vars);
const html = mail_form.html(t_vars);
await debug_templates({text, html}, name);
send_vars.text = text;
send_vars.html = html;
// send both txt and html as attachments
send_email(send_vars);
} catch(err) {
log.error(err);
}
}
const list_unsub = (company, user) => {
return {
unsubscribe: {
url: `${company.unsubscribe}${user.unsubkey}`,
comment: "Unsubscribe"
}
}
}
const reset_form = await load_templates("reset_email");
export const reset = async (job) => {
log.debug(["Received reset with", job.data]);
try {
assert(job.data.user, "job.data.user is required");
const email = job.data.user.email;
const user_id = job.data.user.id;
const browser = job.data.browser || "None";
const ip_address = job.data.ip_address || "None";
assert(email, "Email is required");
assert(user_id !== undefined, "User user_id is undefined.");
const user = await User.first({id: user_id});
assert(user.email === email, `Email ${email} doesn't match user ${user.id}'s email: ${user.email}`);
if(user.reset_sent_at &&
differenceInHours(Date.now(), user.reset_sent_at) < RESET_HOURS_MAX)
{
// prevent repeated high speed reset attempts by using the advanced technolog of...time
log.warn(`User ${user.id} reset request time remaining not long enough, ignoring their request.`);
// update the reset count so they can only attempt this a certain number of times
await User.update({id: user.id}, { reset_count: user.reset_count + 1 });
} else {
// reset is good, all variables are good, so process the request
user.reset_code = User.random_hex(RESET_CODE_SIZE);
await User.update({id: user.id}, {reset_code: user.reset_code, reset_sent_at: Date.now()});
const reset_data = { company, user, browser, ip_address, reset_code: user.reset_code };
const text = reset_form.txt(reset_data);
const html = reset_form.html(reset_data);
await debug_templates({text, html}, "reset_email");
// send both txt and html as attachments
send_email({
from: company.mail,
to: user.email,
list: list_unsub(company, user),
subject: `Reset password request for ${company.website}`,
text, html
});
}
} catch(err) {
log.error(err);
}
}
const reset_finished_form = await load_templates("reset_finished");
export const reset_finished = async (job) => {
try {
const user = job.data.user;
const browser = job.data.browser || "None";
const ip_address = job.data.ip_address || "None";
// update the user's password now and then send the email
await User.update({id: user.id}, {
password: user.password,
reset_code: null,
reset_sent_at: null,
reset_count: 0
});
const reset_finished_data = { company, user, browser, ip_address };
const text = reset_finished_form.txt(reset_finished_data);
const html = reset_finished_form.html(reset_finished_data);
await debug_templates({text, html}, "reset_finished");
// send both txt and html as attachments
send_email({
from: company.mail,
to: user.email,
list: list_unsub(company, user),
subject: `Reset password completed for ${company.website}`,
text, html
});
} catch(err) {
log.error(err);
}
}
const receipt_form = await load_templates("receipt");
export const receipt = async (job) => {
const {user, product_id, payment_id} = job.data;
const payment = await Payment.first({id: payment_id});
assert(payment, `Failed to find payment ID ${payment_id}`);
const product = await Product.first({id: product_id});
assert(product, `Failed to find course ID ${product_id}`);
generic_emailer("receipt",
user, receipt_form, { company, course, payment, user },
{ from: company.mail,
to: user.email,
list: list_unsub(company, user),
subject: `Your ${company.product} Receipt` }
);
}
const register_form = await load_templates("register_email");
export const registration = async (job) => {
const user = job.data.user;
generic_emailer("register_email",
user, register_form, { company, user }, {
from: company.mail,
to: user.email,
list: list_unsub(company, user),
subject: `Registration for ${company.name}`
});
}
const welcome_form = await load_templates("welcome_email");
export const welcome = async (job) => {
const user = job.data.user;
generic_emailer("welcome_email",
user, welcome_form, { company, user }, {
from: company.mail,
to: user.email,
list: list_unsub(company, user),
subject: `Welcome to ${company.name}`
});
}