Skip to content

Commit

Permalink
feature-[167782593]: Add User Can Request Verification email
Browse files Browse the repository at this point in the history
- Implement function to allow users request verification emails
- Include tests for the feature

[Delivers #167782593]
  • Loading branch information
chialuka committed Aug 9, 2019
1 parent cf541a6 commit 4d01d19
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 28 deletions.
3 changes: 2 additions & 1 deletion server/controllers/Sessions.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class Sessions {
if (!isValid && !user.verified) {
await Session.update({ active: false }, { where: { userId: user.id } });
return serverResponse(res, 403, {
error: 'please verify your email address'
error: 'please verify your email address',
email: user.email
});
}
await Session.create({
Expand Down
20 changes: 20 additions & 0 deletions server/controllers/Users.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ class Users {
return serverError(res);
}
}

/** @name resendVerificationEmail
* @async
* @static
* @param {Object} req express request object
* @param {Object} res express response object
* @returns {JSON} Json response to the user
*/
static async resendVerificationEmail(req, res) {
try {
const { email } = req.params;
const user = await User.findByEmail(email);
if (!user) return serverResponse(res, 404, { error: 'user not found' });
const token = generateToken({ id: user.id }, '24h');
sendVerificationEmail({ ...user, token });
return serverResponse(res, 200, { message: 'email sent successfully' });
} catch (error) {
return serverError(res);
}
}
}

export default Users;
69 changes: 43 additions & 26 deletions server/helpers/emailTemplates.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,49 @@ const { SERVER_URL, BASE_URL } = process.env;
const sendVerificationEmail = (data) => {
const { firstName, email, token } = data;
const content = `
<body style="background-color: white; font-family: Montserrat; color: #2B2B2B">
<h1>Authors <span style="color: #D7B914">Haven</span></h1>
<div style="font-size: 16px;">
<div>
<p>Hi ${firstName},</p>
<p>Welcome to Authors Haven. Your amazing journey has started!</p>
<p>To continue enjoying the amazing benefits of your account,
please verify your email.</p>
<p>By clicking on the button below,
you are confirming that this is your email address.</p>
<p style="margin: 20px; text-align: center">
<a style="text-decoration:none; background-color: #505050;
padding:15px; color:white"
href=${SERVER_URL}${BASE_URL}/users/verifyEmail/${token}>
Verify Email
</a>
</p>
</div>
<p style="margin-bottom: 15px">Remember to update
your story preferences so we can serve you with a customized experience.</p>
<div>
<p style="margin-top: 20px">The Authors Haven Team.</p>
<p style="margin-top: 10px; color: #D7B914">© 2019 AUTHORS HAVEN</p>
</div>
</div>
</body>
<html>
<head>
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
<style>
body { font-family: Montserrat; font-style: normal; color: #505050}
.logo { font-weight: normal;font-size: 30px;line-height: 37px;color:#505050; margin-left:20px } .container { margin: 0 7% } .forget__password { font-weight: 500; font-size: 22px; line-height: 30px; text-align:center } button { background: #505050; color: #ffffff; width: 205px; height: 40px; display: block; margin:auto; margin-top:40px; decoration: none } button:focus {outline:0;} .near__foot { margin-top:40px; width: 100%; height: 56px; background: #505050; } .link__text { padding-bottom:50px; margin: 30px 45px; color: #ffffff; font-size: 12px; } .link__text span { color: #D7B914 } .footer { display: flex; justify-content: space-around; margin-top: 20px; margin-bottom:40px } .inner_body { color: #505050 }
</style>
</head>
<body>
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
<div class="container">
<div><h1 class="logo">Authors <span style="color: #D7B914">Haven</span></h1></div>
<div style="border: 0.5px solid rgba(0, 0, 0, 0.1);width:100%"></div>
<div style="margin:0px 45px">
<div class="inner__body"><p>Hi ${firstName},</p>
<p>Welcome to Authors Haven. Your amazing journey has started!</p>
<p style="line-height: 26px">
<p>To continue enjoying the amazing benefits of your account,
please verify your email.</p>
<p>By clicking on the button below,
you are confirming that this is your email address.</p></div>
<a style="text-decoration: none;" href=${SERVER_URL}${BASE_URL}/users/verifyEmail/${token}><button style="background: #505050; color: #ffffff; width: 205px; height: 40px; display: block; margin:auto; margin-top:40px; decoration: none; font-size:14px"> Verify Email</button></a>
<p style="margin:30px 0px">
The Authors Haven Team</p>
</div>
</div>
<div class="near__foot">
<p class="link__text">If you are having trouble with the above button, copy and paste the URL below into your browser.
<a style="color:#D7B914" >${SERVER_URL}${BASE_URL}/users/verifyEmail/${token}></a></p>
</div>
<div style="border: 0.5px solid rgba(0, 0, 0, 0.1);width:100%"></div>
<div class="footer">
</div>
</div>
</body>
</html>
`;
return sendEmail(email, 'Verify Email', content);
};
Expand Down
1 change: 1 addition & 0 deletions server/routes/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ const { validateUserSignup, verifyToken } = middlewares;

route.post('/create', validateUserSignup, Users.create);
route.get('/verifyEmail/:token', verifyToken, Users.verifyUserEmail);
route.get('/verificationEmail/:email', Users.resendVerificationEmail);

export default route;
5 changes: 4 additions & 1 deletion test/users/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import * as signUp from './signup.test';
import * as sessions from './sessions.test';
import * as verifyEmail from './emailVerify.test';
import * as resendEmails from './resendVerifyEmail';

export { signUp, sessions, verifyEmail };
export {
signUp, sessions, verifyEmail, resendEmails
};
69 changes: 69 additions & 0 deletions test/users/resendVerifyEmail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import chai, { expect } from 'chai';
import chaiHttp from 'chai-http';
import { config } from 'dotenv';
import sinon from 'sinon';
import app from '../../server';
import models from '../../server/database/models';
import userData from './__mocks__/user';
import { generateToken } from '../../server/helpers';

config();

chai.use(chaiHttp);

const { BASE_URL } = process.env;

const { User } = models;

const { rightUserWithEmail } = userData;

describe('Resend Verification Email', () => {
const email = rightUserWithEmail.userLogin;
context('when a user requests a new verification email', () => {
it('sends the email to the user', async () => {
const response = await chai
.request(app)
.get(`${BASE_URL}/users/verificationEmail/${email}`);
expect(response).to.have.status(200);
expect(response.body.message).to.equal('email sent successfully');
});
});

context('when user clicks the resent verification link', () => {
it("verifies the user's email", async () => {
const token = generateToken({ id: 1 });
const response = await chai
.request(app)
.get(`${BASE_URL}/users/verifyEmail/${token}`);
expect(response).to.have.status(200);
expect(response.body.message).to.equal('email verification successful');
});
});

context('when a wrong email is supplied', () => {
it('returns a not found error', async () => {
const response = await chai
.request(app)
.get(`${BASE_URL}/users/verificationEmail/odogwu@odogwu.com`);
expect(response).to.have.status(404);
expect(response.body.error).to.equal('user not found');
});
});

context('when there is a server error', () => {
it('throws an error', async () => {
const stub = sinon.stub(User, 'findByEmail');
const error = new Error('server error, this will be resolved shortly');
stub.yields(error);
const res = await chai
.request(app)
.get(`${BASE_URL}/users/verificationEmail/${email}`);
expect(res).to.have.status(500);
expect(res.body).to.include.key('error');
expect(res.body.error).to.equal(
'server error, this will be resolved shortly'
);
stub.restore();
});
});
});

0 comments on commit 4d01d19

Please sign in to comment.