-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(reset-password): reset password via email
- add nodemailer - write send mail functionalities - write reset password functionalities - write tests [Delivers #166789994]
- Loading branch information
Showing
14 changed files
with
490 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
DATABASE_URL=postgres://wmqxaqjr:tTHUvMlywe2owxdrqEaofzdC2RKF4XYp@raja.db.elephantsql.com:5432/wmqxaqjr | ||
DATABASE_TEST=postgres://wmqxaqjr:tTHUvMlywe2owxdrqEaofzdC2RKF4XYp@raja.db.elephantsql.com:5432/wmqxaqjr | ||
SECRET=qwertyuiop[]\';lkjhgfdsa`zxcvbnm,./+_)(*&^%$#@!) | ||
DATABASE_URL=postgresql://dbusername:dbpassword@localhost:5432/dbname | ||
DATABASE_TEST=postgresql://dbusername:dbpassword@localhost:5432/dbnamefortest | ||
|
||
SENDER_EMAIL= | ||
SENDER_PASS= | ||
|
||
SECRET= | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ logs | |
*.log | ||
.dist | ||
.DS_Store | ||
.vscode/ | ||
|
||
npm-debug.log* | ||
# Runtime data | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import jwt from 'jsonwebtoken'; | ||
import dotenv from 'dotenv'; | ||
import models from '../models'; | ||
import sendEmail from '../helpers/sendEmail'; | ||
import Auth from '../helpers/auth'; | ||
|
||
dotenv.config(); | ||
|
||
const { users } = models; | ||
|
||
const { SECRET } = process.env; | ||
const expirationTime = { | ||
expiresIn: '1day', | ||
}; | ||
|
||
/** | ||
* @user controller | ||
* @exports | ||
* @class | ||
*/ | ||
class ResetPasswordController { | ||
/** | ||
* Send password reset email. | ||
* @param {object} req request | ||
* @param {object} res response. | ||
* @returns {object} response. | ||
*/ | ||
static async sendResetLinkEmail(req, res) { | ||
const user = { | ||
email: req.body.email, | ||
}; | ||
try { | ||
const checkUser = await users.findOne({ | ||
where: { | ||
email: user.email, | ||
} | ||
}); | ||
if (checkUser) { | ||
const payload = { | ||
email: checkUser.email, | ||
}; | ||
const token = jwt.sign(payload, SECRET, expirationTime); | ||
req.body.token = token; | ||
req.body.template = 'resetPassword'; | ||
sendEmail(user.email, token, 'resetPassword'); | ||
return res.status(200).send({ message: 'We have e-mailed a password reset link, Check your email!' }); | ||
} | ||
return res.status(404).json({ error: 'The email provided does not exist' }); | ||
} catch (error) { | ||
return res.status(500).json({ error: `${error}` }); | ||
} | ||
} | ||
|
||
/** | ||
* get the reset password token. | ||
* @param {object} req request. | ||
* @param {object} res response. | ||
* @returns {object} response. | ||
*/ | ||
static getToken(req, res) { | ||
return res.send({ token: req.params.token }); | ||
} | ||
|
||
/** | ||
* Resets password. | ||
* @param {object} req request. | ||
* @param {object} res response. | ||
* @returns {object} response. | ||
*/ | ||
static async resetPassword(req, res) { | ||
const password = Auth.hashPassword(req.body.password); | ||
const { token } = req.body; | ||
try { | ||
const decoded = await jwt.decode(token, SECRET); | ||
if (decoded) { | ||
const checkUpdate = await users.update( | ||
{ | ||
password, | ||
}, | ||
{ | ||
where: { | ||
email: decoded.email, | ||
} | ||
} | ||
); | ||
if (checkUpdate.length >= 1) { | ||
return res.status(200).json({ message: 'Your password was reset successfully' }); | ||
} | ||
} | ||
return res.status(401).json({ error: 'Invalid token' }); | ||
} catch (error) { | ||
return res.status(500).send({ error: error.message }); | ||
} | ||
} | ||
} | ||
|
||
export default ResetPasswordController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import dotenv from 'dotenv'; | ||
|
||
dotenv.config(); | ||
const clientUrl = (process.env.NODE_ENV === 'production') ? 'https://ah-92explorers-api.herokuapp.com' : 'http://127.0.0.1:3000'; | ||
|
||
/** | ||
* An object module that holds mails' templates | ||
* @exports email/templates | ||
*/ | ||
const emailTemplates = { | ||
resetPassword: { | ||
from: '', | ||
to: '', | ||
subject: 'Password reset', | ||
html: `<div style="font-family:Avenir,Helvetica,sans-serif;box-sizing:border-box;padding:35px;"> | ||
<h1 style="color: #444;">Authors Haven</h1> | ||
<p style="font-family:Avenir,Helvetica,sans-serif;box-sizing:border-box;color:#74787e;font-size:16px;line-height:1.5em;margin-top:0;text-align:left">You are receiving this email because we received a password reset request for your account. Click the blue button below to reset the password. If you did not request a password reset, no further action is required.</p> | ||
<p><a style="background-color: #3097d1; border: 2px solid #3097d1; padding: 8px; color: #fff; font-size: 16px; text-decoration: none;cursor: pointer;" href="${clientUrl}/api/reset-password/$token">Reset Password</a> | ||
</a></p> | ||
<p style="color:#74787e;font-size:16px;line-height:1.5em;margin-top:0;text-align:left">Thank you for using our application!</p> | ||
<p style="color:#74787e;font-size:16px;line-height:1.5em;margin-top:0;">Regards,<br>Authors Haven</p> | ||
</div>` | ||
}, | ||
}; | ||
|
||
export default { emailTemplates }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import nodemailer from 'nodemailer'; | ||
import { email } from '../config/index'; | ||
import Templates from './emailTemplates'; | ||
|
||
const { emailTemplates } = Templates; | ||
/** | ||
* Class module to send email | ||
* @exports | ||
* @class | ||
*/ | ||
class Mailer { | ||
/** | ||
* Initialize user and pass | ||
* @constructor | ||
* @param {string} _userEmail - User email | ||
*/ | ||
constructor(_userEmail) { | ||
this.userEmail = _userEmail; | ||
this.senderEmail = email.user; | ||
this.senderPass = email.pass; | ||
} | ||
|
||
/** | ||
* Adds a token. | ||
* @param {string} token token | ||
* @param {string} template email. | ||
* @returns {object} response. | ||
*/ | ||
async addTokenToEmail(token, template) { | ||
const mailOptions = emailTemplates[template]; | ||
mailOptions.from = this.senderEmail; | ||
mailOptions.to = this.userEmail; | ||
const addToken = mailOptions.html.replace('$token', token); | ||
mailOptions.html = addToken; | ||
try { | ||
const response = await this.sendEmail(mailOptions); | ||
return response; | ||
} catch (error) { | ||
return `${error}`; | ||
} | ||
} | ||
|
||
/** | ||
* Send email | ||
* @param {Object} mailOptions - Email template | ||
* @returns {object} response. | ||
*/ | ||
async sendEmail(mailOptions) { | ||
const transporter = nodemailer.createTransport({ | ||
service: 'gmail', | ||
auth: { | ||
user: this.senderEmail, | ||
pass: this.senderPass | ||
} | ||
}); | ||
transporter.sendMail(mailOptions); | ||
} | ||
} | ||
export default Mailer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Mailer from './mailer'; | ||
|
||
/** | ||
* Call mailer class to send email to the user | ||
* @param {string} userEmail - User email account for sending email to | ||
* @param {string} token - Token that added to email sent | ||
* @param {template} template email templates | ||
* @returns {object} response. | ||
*/ | ||
const sendEmail = async (userEmail, token, template) => { | ||
try { | ||
const mailer = new Mailer(userEmail); | ||
await mailer.addTokenToEmail(token, template); | ||
} catch (error) { | ||
return `Email failed: ${error.message}`; | ||
} | ||
}; | ||
|
||
export default sendEmail; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.