create-benm-app
Version:
Boilerplate for REST API with Node.js, ExpressJS, and MongoDB
353 lines (349 loc) • 11.8 kB
JavaScript
const UserModel = require("../models/UserModel");
const { body,validationResult } = require("express-validator");
const { check } = require("express-validator");
//helper file to prepare responses.
const apiResponse = require("../helpers/apiResponse");
const utility = require("../utility/utility");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const mailer = require("../helpers/mailer");
const constant = require("../constants/mailTemplate");
/**
*
* @description Register user.
* @param {string} firstName
* @param {string} lastName
* @param {string} email
* @param {string} password
*
* @returns {Object}
*/
exports.register = [
// Validate fields.
body("firstName").isAlpha("en-US", {ignore: " "}).isLength({ min: 1 }).trim().withMessage("First name must be specified.")
.isAlphanumeric().withMessage("First name has non-alphanumeric characters."),
body("lastName").isAlpha("en-US", {ignore: " "}).isLength({ min: 1 }).trim().withMessage("Last name must be specified.")
.isAlphanumeric().withMessage("Last name has non-alphanumeric characters."),
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address.").custom((value) => {
return UserModel.findOne({email : value}).then((user) => {
if (user) {
if(user.isConfirmed){
// User already exists.
return Promise.reject({id:0, msg: "E-mail already in used."});
}else{
// Your email is not verified.
return Promise.reject({id:1, msg: "Your Email-id is already registered but not verified. Please check your email and verify your account."});
}
}
});
}),
body("password").isLength({ min: 6 }).trim().withMessage("Password must be 6 characters or greater."),
// Sanitize fields.
check("firstName").escape(),
check("lastName").escape(),
check("email").escape(),
check("password").escape(),
// Process request after validation and sanitization.
async (req, res) => {
try {
// Extract the validation errors from a request.
const errors = validationResult(req);
if (!errors.isEmpty()) {
// Display sanitized values/errors messages.
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const { firstName, lastName, email, password } = req.body;
//hash input password
const hashPassword = await bcrypt.hash(password,10);
// generate OTP for confirmation
let otp = utility.randomNumber(4);
// Create User object with escaped and trimmed data
var user = new UserModel({
firstName: firstName,
lastName: lastName,
email: email,
password: hashPassword,
confirmOTP: otp,
});
// Html email body
let html = constant.otpMailTemplate(otp);
// Send confirmation email
mailer.send(
email,
"Confirm Account",
html
);
// Save user.
await user.save();
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email
};
return apiResponse.successResponseWithData(res,"Registration Success.", userData);
}
} catch (error) {
console.log(error);
//throw error in json response with status 500.
return apiResponse.ErrorResponse(res, error.message);
}
}];
/**
*
* @description User login.
* @param {string} email
* @param {string} password
*
* @returns {Object}
*/
exports.login = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
body("password").isLength({ min: 1 }).trim().withMessage("Password must be specified."),
check("email").escape(),
check("password").escape(),
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const user = await UserModel.findOne({email : req.body.email});
if (user) {
//Check account confirmation.
if(user.isConfirmed && user.status){
//Compare given password with db's hash.
const verifyPassword = await bcrypt.compare(req.body.password,user.password);
if(verifyPassword){
// Check User's account active or not.
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
};
//Prepare JWT token for authentication
const jwtPayload = userData;
const jwtData = {
expiresIn: process.env.JWT_TIMEOUT_DURATION,
};
const secret = process.env.JWT_SECRET;
//Generated JWT token with Payload and secret.
userData.token = await jwt.sign(jwtPayload, secret, jwtData);
return apiResponse.successResponseWithData(res,"Login Success.", userData);
} else {
return apiResponse.unauthorizedResponse(res, "Email or Password wrong.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Account is not verified. Please verified your account.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Email or Password wrong.");
}
}
} catch (error) {
return apiResponse.ErrorResponse(res, error.message);
}
}];
/**
*
* @description verify OTP
* @param {string} email
* @param {Integer} otp
*
* @returns {Object}
*/
exports.verifyAccount = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
body("otp").isNumeric().isLength({ min: 4 }).trim().withMessage("OTP must be specified."),
check("email").escape(),
check("otp").escape(),
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const { email, otp } = req.body;
var query = {email : email};
const user= await UserModel.findOne(query);
if (user) {
//Check already confirm or not.
if(!user.isConfirmed){
//Check account confirmation.
if(user.confirmOTP == otp){
//Update user as confirmed
const updateUserOTPStatus = await UserModel.findOneAndUpdate(query, {
isConfirmed: 1,
confirmOTP: null
});
if(!updateUserOTPStatus){
return apiResponse.ErrorResponse(res, "Error in update user.");
}
// Html email body
let html = constant.accountIsConfirmedTemplate(email, user.firstName, user.lastName);
// Send confirmation email
mailer.send(
email,
"Your Account is Verified",
html
);
return apiResponse.successResponse(res,"Account is verified successfully.");
}else{
return apiResponse.unauthorizedResponse(res, "Invalid OTP.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Account is already verified.");
}
}else{
return apiResponse.unauthorizedResponse(res, "email not found.");
}
}
} catch (err) {
return apiResponse.ErrorResponse(res, err);
}
}];
/**
*
* @description Resend verification OTP.
* @param {string} email
*
* @returns {Object}
*/
exports.resendVerificationOtp = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
check("email").escape(),
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const user = await UserModel.findOne({email : req.body.email});
if (user) {
//Check already confirm or not.
if(!user.isConfirmed){
// Generate otp
let otp = utility.randomNumber(4);
// Html email body
let html = constant.otpMailTemplate(otp);
// Send confirmation email
await mailer.send(
req.body.email,
"Confirm Account",
html
);
// Update otp
user.confirmOTP = otp;
// Save user.
await user.save();
return apiResponse.successResponse(res,"new OTP sent.");
}else{
return apiResponse.unauthorizedResponse(res, "Account already confirmed.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Specified email not found.");
}
}
} catch (error) {
return apiResponse.ErrorResponse(res, error.message);
}
}];
/**
*
* @description Forgot Password.
* @param {string} email
*
* @returns {Object}
*/
exports.forgotPassword = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
check("email").escape(),
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const user = await UserModel.findOne({email : req.body.email});
if (user) {
// Generate otp
let ForgotPasswordUUID = await utility.createUUID();
var host = req.get("host");
const link = req.protocol+"://"+host+"/auth/reset-password/"+ForgotPasswordUUID+"/"+user._id;
// Html email body
let html = constant.forgotPasswordMailTemplate(link, user.firstName);
// Send confirmation email
await mailer.send(
req.body.email,
"Forgot Password",
html
);
user.forgotPasswordId = ForgotPasswordUUID;
// Save user.
await user.save();
return apiResponse.successResponse(res,"Forgot Password Link Sent.");
}else{
return apiResponse.unauthorizedResponse(res, "Email not found.");
}
}
} catch (error) {
return apiResponse.ErrorResponse(res, error.message);
}
}
];
/**
* @description Reset Password.
* @param {string} password
* @param {string} confirmPassword
* @param {string} forgotPasswordId
*
* @returns {Object}
*/
exports.resetPassword = [
body("password").isLength({ min: 1 }).trim().withMessage("Password must be specified.")
.isLength({ min: 6 }).withMessage("Password must be at least 6 characters long."),
body("confirmPassword").isLength({ min: 1 }).trim().withMessage("Confirm Password must be specified.")
.custom((value, { req }) => {
if (value !== req.body.password) {
throw new Error("Password confirmation does not match password.");
}
return value;
}),
body("uuid").isLength({ min: 1 }).trim().withMessage("id must be specified.")
.isLength({ min: 6 }).withMessage("id is invalid"),
body("userId").isLength({ min: 1 }).trim().withMessage("id must be specified.")
.isLength({ min: 6 }).withMessage("userId is invalid"),
check("password").escape(),
check("confirmPassword").escape(),
check("uuid").escape(),
check("userId").escape(),
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
const { password, uuid, userId } = req.body;
const user = await UserModel.findOne({forgotPasswordId : uuid, _id: userId});
if (user) {
const hashPassword = await bcrypt.hash(password,10);
user.password = hashPassword;
user.forgotPasswordId = null;
// Save user.
await user.save();
return apiResponse.successResponse(res,"Password reset successfully.");
}else{
return apiResponse.unauthorizedResponse(res, "Link is invalid, Please try with valid link.");
}
}
} catch (error) {
return apiResponse.ErrorResponse(res, error.message);
}
}
];