diff --git a/src/controllers/authentication/passwordReset.js b/src/controllers/authentication/passwordReset.js new file mode 100644 index 0000000..6a17fb5 --- /dev/null +++ b/src/controllers/authentication/passwordReset.js @@ -0,0 +1,40 @@ +import bcrypt from 'bcryptjs'; +import { User } from '../../models'; +import Auth from '../../middlewares/authenticator'; +import { responseFormat, errorResponseFormat } from '../../utils/index'; + +export const forgotPassword = async (req, res) => { + try { + const { email } = req.body; + const user = await User.findOne({ where: { email } }); + if (!user) { return res.status(404).json(errorResponseFormat({ status: 'fail', message: 'Account associated with email cannot with found' })); } + const passwordResetToken = Auth.generateToken({ email }); + await user.update({ passwordResetToken, resetTokenExpires: Date.now() + 36000 }); + return res.status(200).json(responseFormat({ status: 'success', data: `Password reset instruction was successfully sent to ${req.body.email}` })); + } catch (error) { + return res.status(500).json({ status: 'error', message: 'Something went wrong' }); + } +}; + +export const resetPassword = async (req, res) => { + try { + const { resetToken } = req.params; + const user = await User.findOne({ where: { passwordResetToken: resetToken, } }); + if (!user) { return res.status(404).json(errorResponseFormat({ status: 'fail', message: 'Password link has expired!' })); } + return res.status(200).json(responseFormat({ status: 'success', data: 'Password reset link is valid' })); + } catch (error) { + return res.status(500).json({ status: 'error', message: 'Something went wrong' }); + } +}; + +export const updatePassword = async (req, res) => { + try { + const { password } = req.body; + const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); + // eslint-disable-next-line max-len + await User.update({ password: hashPassword, passwordResetToken: null, resetTokenExpires: null }); + return res.status(202).json(responseFormat({ status: 'success', data: 'Password was successfully updated!' })); + } catch (error) { + return res.status(500).json({ status: 'error', message: 'Something went wrong' }); + } +}; diff --git a/src/migrations/20190329164503-create-user.js b/src/migrations/20190329164503-create-user.js index 91b3ddc..b4f05d4 100644 --- a/src/migrations/20190329164503-create-user.js +++ b/src/migrations/20190329164503-create-user.js @@ -46,6 +46,12 @@ export default { type: Sequelize.ENUM('admin', 'author', 'user'), defaultValue: 'user', }, + passwordResetToken: { + type: Sequelize.STRING, + }, + resetTokenExpires: { + type: Sequelize.DATE, + }, createdAt: { type: Sequelize.DATE, }, diff --git a/src/models/user.js b/src/models/user.js index 7cbaa79..8512aeb 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -46,6 +46,12 @@ export default (sequelize, DataTypes) => { type: DataTypes.TEXT, allowNull: false, }, + passwordResetToken: { + type: DataTypes.STRING, + }, + resetTokenExpires: { + type: DataTypes.DATE, + }, notification: DataTypes.BOOLEAN, role: DataTypes.ENUM('admin', 'author', 'user'), }, diff --git a/src/routers/index.js b/src/routers/index.js index 588954c..816e9f4 100755 --- a/src/routers/index.js +++ b/src/routers/index.js @@ -5,6 +5,7 @@ import { AddArticles, UpdateArticle, DeleteArticle } from '../controllers/articl import checkFields from '../middlewares/auth/loginValidator'; import socialRedirect from '../controllers/authentication/socialRedirect'; import { login, createUser } from '../controllers/authentication/user'; +import { forgotPassword, resetPassword, updatePassword } from '../controllers/authentication/passwordReset'; import checkBody from '../middlewares/signUpValidator'; @@ -35,6 +36,12 @@ router router.post('/login', checkFields, passportAuth, login); +// Routes for password reset +router + .post('/forgot', forgotPassword) + .get('/reset/:resetToken', resetPassword) + .patch('/updatePassword', updatePassword); + // Route for facebook Authentication router.get('/auth/facebook', passport.authenticate('facebook', { authType: 'rerequest', scope: ['email'] }));