feat: Implement draft version of reset password email (#949)

This commit is contained in:
Ömer Faruk Aydın
2023-02-24 00:25:10 +01:00
committed by GitHub
parent bd02b7574a
commit a0815b06a6
9 changed files with 141 additions and 1 deletions

View File

@@ -45,6 +45,7 @@
"graphql-shield": "^7.5.0",
"graphql-tools": "^8.2.0",
"graphql-type-json": "^0.3.2",
"handlebars": "^4.7.7",
"http-errors": "~1.6.3",
"jsonwebtoken": "^9.0.0",
"knex": "^2.4.0",

View File

@@ -32,6 +32,12 @@ type AppConfig = {
bullMQDashboardPassword: string;
telemetryEnabled: boolean;
requestBodySizeLimit: string;
smtpHost: string;
smtpPort: number;
smtpSecure: boolean;
smtpUser: string;
smtpPassword: string;
fromEmail: string;
licenseKey: string;
};
@@ -92,6 +98,12 @@ const appConfig: AppConfig = {
webhookUrl,
telemetryEnabled: process.env.TELEMETRY_ENABLED === 'false' ? false : true,
requestBodySizeLimit: '1mb',
smtpHost: process.env.SMTP_HOST,
smtpPort: parseInt(process.env.SMTP_PORT || '587'),
smtpSecure: process.env.SMTP_SECURE === 'true',
smtpUser: process.env.SMTP_USER,
smtpPassword: process.env.SMTP_PASSWORD,
fromEmail: process.env.FROM_EMAIL,
licenseKey: process.env.LICENSE_KEY,
};

View File

@@ -1,4 +1,9 @@
import User from '../../models/user';
import emailQueue from '../../queues/email';
import {
REMOVE_AFTER_30_DAYS_OR_150_JOBS,
REMOVE_AFTER_7_DAYS_OR_50_JOBS,
} from '../../helpers/remove-job-configuration';
type Params = {
input: {
@@ -16,7 +21,24 @@ const forgotPassword = async (_parent: unknown, params: Params) => {
}
await user.generateResetPasswordToken();
// TODO: Send email with reset password link
const jobName = `Reset Password Email - ${user.id}`;
const jobPayload = {
email: user.email,
subject: 'Reset Password',
template: 'reset-password-instructions',
params: {
token: user.resetPasswordToken,
},
};
const jobOptions = {
removeOnComplete: REMOVE_AFTER_7_DAYS_OR_50_JOBS,
removeOnFail: REMOVE_AFTER_30_DAYS_OR_150_JOBS,
};
await emailQueue.add(jobName, jobPayload, jobOptions);
return;
};

View File

@@ -0,0 +1,12 @@
import * as path from 'path';
import * as fs from 'fs';
import * as handlebars from 'handlebars';
const compileEmail = (emailPath: string, replacements: object = {}): string => {
const filePath = path.join(__dirname, `../views/emails/${emailPath}.ee.hbs`);
const source = fs.readFileSync(filePath, 'utf-8').toString();
const template = handlebars.compile(source);
return template(replacements);
};
export default compileEmail;

View File

@@ -0,0 +1,14 @@
import nodemailer from 'nodemailer';
import appConfig from '../config/app';
const mailer = nodemailer.createTransport({
host: appConfig.smtpHost,
port: appConfig.smtpPort,
secure: appConfig.smtpSecure,
auth: {
user: appConfig.smtpUser,
pass: appConfig.smtpPassword,
},
});
export default mailer;

View File

@@ -0,0 +1,25 @@
import process from 'process';
import { Queue } from 'bullmq';
import redisConfig from '../config/redis';
import logger from '../helpers/logger';
const CONNECTION_REFUSED = 'ECONNREFUSED';
const redisConnection = {
connection: redisConfig,
};
const emailQueue = new Queue('email', redisConnection);
process.on('SIGTERM', async () => {
await emailQueue.close();
});
emailQueue.on('error', (err) => {
if ((err as any).code === CONNECTION_REFUSED) {
logger.error('Make sure you have installed Redis and it is running.', err);
process.exit();
}
});
export default emailQueue;

View File

@@ -0,0 +1,16 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Hello {{ email }}
Someone has requested a link to change your password, and you can do this through the link below.
<a href="/reset-password">Change my password</a>
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.
</body>
</html>

View File

@@ -3,6 +3,7 @@ import './helpers/check-worker-readiness';
import './workers/flow';
import './workers/trigger';
import './workers/action';
import './workers/email';
import telemetry from './helpers/telemetry';
telemetry.setServiceType('worker');

View File

@@ -0,0 +1,37 @@
import { Worker } from 'bullmq';
import redisConfig from '../config/redis';
import logger from '../helpers/logger';
import mailer from '../helpers/mailer.ee';
import compileEmail from '../helpers/compile-email.ee';
import appConfig from '../config/app';
export const worker = new Worker(
'email',
async (job) => {
const { email, subject, templateName, params } = job.data;
await mailer.sendMail({
to: email,
from: appConfig.fromEmail,
subject: subject,
html: compileEmail(templateName, params),
});
},
{ connection: redisConfig }
);
worker.on('completed', (job) => {
logger.info(
`JOB ID: ${job.id} - ${job.data.subject} email sent to ${job.data.email}!`
);
});
worker.on('failed', (job, err) => {
logger.info(
`JOB ID: ${job.id} - ${job.data.subject} email to ${job.data.email} has failed to send with ${err.message}`
);
});
process.on('SIGTERM', async () => {
await worker.close();
});