This is the code that runs https://bandolier.learnjsthehardway.com/ for you to review. It uses the https://git.learnjsthehardway.com/learn-javascript-the-hard-way/bandolier-template to create the documentation for the project.
https://bandolier.learnjsthehardway.com/
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.
171 lines
5.1 KiB
171 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}`
|
|
});
|
|
}
|
|
|