diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.js index 0ad7676..5f94915 100644 --- a/app/controllers/auth.controller.js +++ b/app/controllers/auth.controller.js @@ -2,9 +2,12 @@ const db = require('../../models'), bcrypt = require('bcrypt-nodejs'), jwt = require('jsonwebtoken'), errorMaker = require('../helpers/error.maker'), - roles = require('../helpers/roles'); + roles = require('../helpers/roles'), + uuidv4 = require('uuid/v4'); -const { Donor, Organization } = db; +const sendgrid = require('./sendgrid.controller'); + +const { Donor, Organization, sequelize } = db; // Find a Donor/Org by email + login with JWT exports.donorLogin = (req, res, next) => { @@ -77,3 +80,77 @@ exports.orgLogin = (req, res, next) => { }) .catch(error => next(error)); }; + +exports.resetPasswordEmail = async (req, res, next) => { + try { + const { email, usertype } = req.query; + + var user; + if (usertype == 'donor') { + user = await sequelize.query( + ` + SELECT id FROM donors + WHERE email = :email`, + { + type: sequelize.QueryTypes.SELECT, + replacements: { email } + } + ); + } else { + user = await sequelize.query( + ` + SELECT id FROM organizations + WHERE email = :email`, + { + type: sequelize.QueryTypes.SELECT, + replacements: { email } + } + ); + } + user = user[0]; + + if (!user) + return res.status(400).json({ + message: 'User not found' + }); + + const CODE = uuidv4(); + const currDate = new Date(); + + sequelize.query( + ` + INSERT INTO password_reset + ( + code, + user_id, + user_type, + created_at, + updated_at + ) + VALUES + ( + :code, + :user_id, + :user_type, + :curr_date, + :curr_date + )`, + { + type: sequelize.QueryTypes.INSERT, + replacements: { + code: CODE, + user_id: user.id, + user_type: usertype, + curr_date: currDate + } + } + ); + + sendgrid.passwordResetEmail(email, CODE); + return res + .status(200) + .json({ message: 'Successfuly sent password reset email!' }); + } catch (e) { + next(e); + } +}; diff --git a/app/controllers/sendgrid.controller.js b/app/controllers/sendgrid.controller.js index 9946761..2928353 100644 --- a/app/controllers/sendgrid.controller.js +++ b/app/controllers/sendgrid.controller.js @@ -79,3 +79,26 @@ exports.testEmail = async (req, res) => { throw error; } }; + +exports.passwordResetEmail = async (receiver, code) => { + return await new Promise(async (resolve, reject) => { + try { + const msg = { + to: receiver, + from: { email: 'no-reply@ucharify.com', name: 'UCharify Security' }, + template_id: 'd-569f804f5e7749cba66bac1994607280', + + substitutionWrappers: ['{{', '}}'], + dynamic_template_data: { + reset_link: `${process.env.WEB_CLIENT}/resetpassword/form`, + subject: 'Reset Your Password' + } + }; + const sentRes = await sgMail.send(msg); + + resolve(); + } catch (e) { + reject(e); + } + }); +}; diff --git a/app/routes/auth.route.js b/app/routes/auth.route.js index e5337e4..7d1fc53 100644 --- a/app/routes/auth.route.js +++ b/app/routes/auth.route.js @@ -10,4 +10,10 @@ router.post('/donor/login', auth.donorLogin); // Check database for org and get token with org role router.post('/org/login', auth.orgLogin); +// Code and send email for reset password +router.get('/resetpassword', auth.resetPasswordEmail); + +// Reset password for either donor or charity after verifying code +router.post('/resetpassword', auth.resetPasswordEmail); + module.exports = router; diff --git a/migrations/20190513064820-create-password-reset.js b/migrations/20190513064820-create-password-reset.js new file mode 100644 index 0000000..7de1f09 --- /dev/null +++ b/migrations/20190513064820-create-password-reset.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable('password_reset', { + code: { + type: Sequelize.STRING, + allowNull: false + }, + user_id: { + type: Sequelize.UUID, + allowNull: false + }, + user_type: { + type: Sequelize.STRING, + allowNull: false + }, + created_at: { + allowNull: false, + type: Sequelize.DATE + }, + updated_at: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: (queryInterface, Sequelize) => { + return queryInterface.dropTable('password_reset'); + } +}; diff --git a/models/PasswordReset.js b/models/PasswordReset.js new file mode 100644 index 0000000..63ceda5 --- /dev/null +++ b/models/PasswordReset.js @@ -0,0 +1,33 @@ +'use strict'; +module.exports = (sequelize, DataTypes) => { + const PasswordReset = sequelize.define( + 'password_reset', + { + code: { + type: Sequelize.STRING, + allowNull: false + }, + user_id: { + type: Sequelize.UUID, + allowNull: false + }, + user_type: { + type: Sequelize.STRING, + allowNull: false + }, + created_at: { + allowNull: false, + type: Sequelize.DATE + }, + updated_at: { + allowNull: false, + type: Sequelize.DATE + } + }, + {} + ); + PasswordReset.associate = function(models) { + // associations can be defined here + }; + return PasswordReset; +};