Skip to content

Commit

Permalink
feat(password-reset): add password reset endpoints
Browse files Browse the repository at this point in the history
- add test for password reset endpoint
- add password reset endpoint routes.
- add update Password service.
- add verify email and send email Helper.
- add password validation userSchema.
- update documentation.

[Delivers #167749954]
  • Loading branch information
daviddamilola committed Sep 14, 2019
1 parent 9689f85 commit a6dc289
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 88 deletions.
29 changes: 6 additions & 23 deletions src/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,6 @@ import transporter from '../utils/transporter';
* @exports UserController
*/
export default class UserController {
/**
* @method
* @description compose email verification
* @static
* @param {string} email
* @param {string} host
* @param {string} token - application url
* @returns {object} object
*/
static composeVerificationMail(email, host, token) {
return {
recipientEmail: `${email}`,
subject: 'Email verification',
body: `<a href='http://${host}/api/v1/users/verifyEmail/${token}'>Verify Your Email</a>`
};
}

/**
* @method
* @description Implements signup endpoint
Expand All @@ -38,7 +21,6 @@ export default class UserController {
*/
static signup(req, res) {
const user = req.body;
const { host } = req.headers;
const msg = 'Kindly confirm the link sent to your email account to complete your registration';
UserService.signup(user).then(response => {
const result = {
Expand All @@ -49,7 +31,7 @@ export default class UserController {
};
const { email } = result;
const token = Helper.generateToken({ id: response.id, email, });
const mailData = UserController.composeVerificationMail(email, host, token);
const mailData = Helper.composeVerificationMail(req, email, token);
sendEmail(transporter(), mailData);
Responses.setSuccess(201, msg, { token, ...result });
return Responses.send(res);
Expand Down Expand Up @@ -95,7 +77,7 @@ export default class UserController {
const emailOptions = Helper.constructResetEmail(req, email);
const validUser = await Helper.verifyExistingEmail(email);
if (validUser) {
sendEmail(transporter, emailOptions);
sendEmail(transporter(), emailOptions);
Responses.setSuccess(200, 'a password reset link has been sent to your email');
return Responses.send(res);
}
Expand Down Expand Up @@ -125,17 +107,18 @@ export default class UserController {
return Responses.send(res);
}
const { password } = req.body;
const [, rowsAffected] = await UserService.resetPassword(password, data.email);
const user = await UserService.resetPassword(password, data.email);
const {
id, email, createdAt, updatedAt
} = rowsAffected;
} = user[1];
Responses.setSuccess(
200,
'successfully updated your password',
{
id, email, createdAt, updatedAt
}
);
return Responses.send(res);
}

/**
Expand All @@ -153,8 +136,8 @@ export default class UserController {
const user = await UserService.findUser(id);
if (email === user.email) {
UserService.updateUser(email);
Responses.setSuccess(200, 'Your account has been verified');
}
Responses.setSuccess(200, 'Your account has been verified');
return Responses.send(res);
}
}
29 changes: 0 additions & 29 deletions src/tests/Email.test.js

This file was deleted.

92 changes: 88 additions & 4 deletions src/tests/user.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import sinonChai from 'sinon-chai';
import Helper from '../utils/Helper';
import app from '../index';
import Helper from '../utils/Helper';
import UserService from '../services/UserService';
Expand Down Expand Up @@ -86,7 +85,7 @@ describe('/POST Signup route', () => {
expect(res.body).to.be.an('object');
expect(res.body.data).to.have.property('token');
expect(res.body).to.have.property('message')
.eql('user account created successfully');
.eql('Kindly confirm the link sent to your email account to complete your registration');
expect(res.body).to.have.property('message');
done(err);
});
Expand Down Expand Up @@ -283,7 +282,7 @@ describe('POST api/v1/users/reset/:token', () => {
done();
});
}).timeout(5000);
})
});

describe('/users/verifyEmail/:token', () => {
before(done => {
Expand All @@ -301,7 +300,7 @@ describe('/users/verifyEmail/:token', () => {
expect(res.body).to.have.property('message');
done();
});
}).timeout(5000);
}).timeout(10000);

it('should return error if token is not provided', done => {
chai
Expand Down Expand Up @@ -329,3 +328,88 @@ describe('/users/verifyEmail/:token', () => {
}).finally(done);
});
});

describe('POST api/v1/users/reset', () => {
it('should send a registered user a reset password link', done => {
chai
.request(app)
.post('/api/v1/users/reset')
.send({
email: 'frank123@gmail.com'
})
.end((err, res) => {
expect(res).to.haveOwnProperty('status');
done();
});
});

it('should send an appropriate message if password reset link is sent ', done => {
chai
.request(app)
.post('/api/v1/users/reset')
.send({
email: 'frank123@gmail.com'
})
.end((err, res) => {
expect(res.body).to.haveOwnProperty('message');
expect(res.status).to.be.equal(200);
done();
});
});
});


describe('POST api/v1/users/reset/:token', () => {
before(done => {
token = Helper.generateToken({ email: 'naimatdavid@mail.com', issued: Date.now(), expiryDate: Date.now() + 36000 });
done();
});
it('should update a user password', done => {
chai
.request(app)
.patch(`/api/v1/users/reset/${Helper.generateToken({ email: 'naimatdavid@mail.com', expiryDate: parseInt(Date.now() + 36000, 10) })}`)
.send({ password: 'Lorem20@$' })
.end((err, res) => {
expect(res.status).to.be.equal(200);
expect(res.body.status).to.be.equal('success');
done();
});
}).timeout(5000);
it('should take the user to a page to reset the password', done => {
chai
.request(app)
.get(`/api/v1/users/reset/${token}`)
.end((err, res) => {
expect(res.status).to.be.equal(200);
done();
});
});
it('should validate the new password', done => {
before(() => {
token = Helper.generateToken({
email: 'naimatdavid@mail.com',
issued: Date.now(),
expiryDate: 3600000
});
});
chai
.request(app)
.patch(`/api/v1/users/reset/${token}`)
.send({ password: 'morem20' })
.end((err, res) => {
expect(res.status).to.be.equal(400);
done();
});
}).timeout(5000);
it('should not update password via an expired link', done => {
chai
.request(app)
.patch(`/api/v1/users/reset/${Helper.generateToken({ email: 'naimatdavid@mail.com', issued: Date.now(), expiryDate: 3600000 })}`)
.send({ password: 'Morem20@$' })
.end((err, res) => {
expect(res.status).to.be.equal(400);
expect(res.body.message).to.be.equal('this address link has expired');
done();
});
}).timeout(5000);
});
27 changes: 22 additions & 5 deletions src/utils/Helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import dotenv from 'dotenv';
import models from '../database/models';
import Responses from './Responses';

<<<<<<< HEAD

dotenv.config();
=======
const secret = process.env.SECRET;
>>>>>>> feat(verify email):verify user email

const secret = process.env.SECRET;
const senderEmail = process.env.EMAIL;
/**
* @class Helper
* @description An helper class containing utility methods
Expand Down Expand Up @@ -73,6 +70,26 @@ export default class Helper {
return false;
}

/**
* @method
* @description compose email verification
* @static
* @param {object} req
* @param {string} email
* @param {string} token - jwt token
* @returns {object} object
*/
static composeVerificationMail(req, email, token) {
const recipients = [email];
const { host } = req.headers;
return {
from: `"Magma Talent Team"<${senderEmail}>`,
to: [...recipients],
subject: 'Email verification',
html: `<a href='http://${host}/api/v1/users/verifyEmail/${token}'>Verify Your Email</a>`
};
}

/**
* @method constructResetEmail
* @description construct a password rest email
Expand Down
19 changes: 0 additions & 19 deletions src/utils/email.js

This file was deleted.

9 changes: 1 addition & 8 deletions src/utils/mailer.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
const senderEmail = process.env.EMAIL;

const sendEmail = (transport, emailData) => new Promise((resolve, reject) => {
transport.sendMail({
from: `"Magma Talent Team"<${senderEmail}>`, // sender address
to: `${emailData.recipientEmail}`,
subject: `${emailData.subject}`, // Subject line
html: `${emailData.body}`
}, (err, info) => (err ? reject(err) : resolve(info)));
transport.sendMail(emailData, (err, info) => (err ? reject(err) : resolve(info)));
});

export default sendEmail;

0 comments on commit a6dc289

Please sign in to comment.