Skip to main content

Register new User, Login User, Delete user, Update User Profile , Forgot/Reset password, Change Password - Node Js , MERN Stack Post 101



Project Folder Architecture will look like this (Setup your Node JS in folder)


========install required package using command - npm install packegeName  for example 
    npm install express 
npm install jsonwebtoken 
npm install bcryptjs  etc. etc.

==================================================================

First create a file  config.env  inwhich we will set various variable with info  

PORT=4000

Database_url = "mongodb://localhost:27017/E-com"

JWT_SECRET = KILVISHKJDKFJKDFJKDKDFKJDSKFSDFKJ  

JWT_EXPIRE = 5d

COOKIE_EXPIRE = 5

SMTP_SERVICE = "gmail"

SMTP_MAIL = 'vasubirla@gmail.com'

SMTP_PASSWORD = 'mtvrqzmxlaroeizh'
//create your own app pass from your google security setting, this is wrong pass

First create Server -  Server.js 
const app = require('./app');
const dotenv = require('dotenv');
const connectDatabase = require('./config/database')

//Uncaught Exception Handling
process.on("uncaughtException",err=>{

    console.log(`error:${err.message}`);
    console.log( `Shutting Down the server due to Uncaught Exception`);
    server.close(()=>{
        process.exit(1)
    })
})


//env File added
dotenv.config({path:"backend/config/config.env"});

//added Database
connectDatabase();


const server=  app.listen(process.env.PORT,()=>{
    console.log(" Server Started at port"+process.env.PORT);
})


//unhandled Promis rejection
process.on("unhandledRejection",err=>{

    console.log(`error:${err.message}`);
    console.log("Shutting Down the server due to unhandled Promise Rejection");

    server.close(()=>{
        process.exit(1)
    })
})




//app.js 
const express = require('express');
const app = express ();

const cookieParser = require('cookie-parser');

const errorMiddleware = require('./middleware/error.js');

const user = require('./routes/userRoute');

//============= middleware section start  ======
app.use(express.json());
app.use(cookieParser());

app.use('/api/v1',user);
app.use('/api/v1',order)

app.use(errorMiddleware); //middleware for error handling


//============= middleware section end ===========
module.exports = app




//Create utils folder and inside it create following supporting files - 
1. errorhander.js - this file is for handling error once so that we dont have  to write error code again and again . 
2. jwttoken.js - this file is to generate unique Token to user and save user info into cookies for authentication for different services like login , change pass, create order , delete Profile - 
without JWT token - it cant not be done -  
3. sendEmail.js -  This file is for sending verification link or reset password link to user's email - 

=========== 1. /utilsfolder/errorhander.js ======================== 
//errorhander.js
class ErrorHander extends Error{

    constructor(message,statusCode){

        super(message)
        this.statuscode = statusCode

        Error.captureStackTrace(this,this.constructor)
    }
}

module.exports = ErrorHander

=================2. /utils/jwtToken.js file ==================== 
// Creating Token and saving in Cookie - jwtToken.js
const sendToken = (user, statusCode, res)=>{

    const token = user.getJWTToken();

    //options for tokens  
        const options = {
            expires: new Date(
                Date.now() + process.env.COOKIE_EXPIRE*24*60*60*1000
            ),
            httpOnly:true
        }

        res.status(statusCode).cookie('token',token,options).json({

            success: true,
            user,
            token
        })
}

module.exports = sendToken


==============3. /utils/sendEmail.js  file ==================   

const nodemailer = require('nodemailer');

const sendEmail = async (options)=>{
     
      process.env.NODE_TLS_REJECT_UNAUTHORIZED='0'

    const transporter = nodemailer.createTransport({
        service: process.env.SMTP_SERVICE,
        auth: {
          user: process.env.SMTP_MAIL,
          pass: process.env.SMTP_PASSWORD
        }
      });


      const mailOptions = {
        from: process.env.SMTP_MAIL,
        to: options.email,
        subject: options.subject,
        html: options.message,
     
      }

      await transporter.sendMail(mailOptions)

}

module.exports = sendEmail



//  Create User Model.js 

//UserModel.js
const mongoose = require('mongoose');
const validator = require('validator');
const { default: isEmail } = require('validator/lib/isemail');
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken');
const crypto = require('crypto')

const userSchema = new mongoose.Schema({

    name: {
        type:String,
        required:[true,"please enter Your name"],
        trim:true
    },
    email: {
        type:String,
        required:[true,"Email is Required"],
        unique:true,
        validate:[validator.isEmail,"Please Enter Valid Email"] ,
        trim:true
    },
    password: {
        type:String,
        required:[true,"please enter Your name"],
        minLength:[6,"Password should be greater than 8 char"],
        select:false
    },
    avatar:{
            public_id:{
                type:String,
                required:true
            },
            url:{
                type:String,
                required:true
            }
        },
    role:{
        type:String,
        default:"user"
    },
    resetPasswordToken:String,
    resetPasswordExpire:Date
})


// convert plain password into hash before(pre) saving user
userSchema.pre("save",async function(next){
    //don't hash on update already existing User
    if(!this.isModified("password")){
        next()
    }
    this.password = await bcrypt.hash(this.password,10)

})

//JWN Token - Generate jwt and store in cookie storage

userSchema.methods.getJWTToken = function(){
        //first parameter is Payload unique ID , second is Secret Key, third is token expire time
    return jwt.sign({id:this._id},process.env.JWT_SECRET,{
        expiresIn: process.env.JWT_EXPIRE
    })
}

//compare Password

userSchema.methods.comparePassword = async function(enteredPassword){

    return await bcrypt.compare(enteredPassword,this.password)

}


// create Token to reset Password

userSchema.methods.getResetPasswordToken = function(){

    const resetToken = crypto.randomBytes(20).toString('hex');

    //hashing and adding to userSchema

    this.resetPasswordToken = crypto.createHash("sha256").update(resetToken).digest("hex");

    this.resetPasswordExpire = Date.now() + 15 * 60 * 1000 ;

    return resetToken;
}



module.exports = mongoose.model("User",userSchema)



//======= create user controller--- UserController.js is below============

const ErrorHander = require('../utils/errorhander');
const catchAsyncError = require('../middleware/catchAsyncError');
const User = require('../models/userModel.js');
const sendToken = require('../utils/jwtToken');
const sendEmail = require('../utils/sendEmail.js')

const crypto = require('crypto');
const { access } = require('fs');


//Register a new User

exports.registerUser = catchAsyncError(async(req,res,next)=>{

    const{name,email,password} = req.body
    const user = await User.create({
        name,email,password,
        avatar:{
            public_id:"this is temp id",
            url:"profilepicsample url",
        }
    })

    sendToken(user,200,res)
})
//===== after creating each module import and use it in UserRoute.js
then test it on postman (refer following Image of testing register API)



//Login user

exports.loginUser = catchAsyncError(async(req,res,next)=>{

        const {email,password} = req.body;

        //if user don't enter email password
        if(!email || !password){
            next(new ErrorHander("Please Enter Email and Password",400))
        }

         const user =await User.findOne({email}).select("+password") ; // select because we set false in UserModel Password selection

        if(!user){
            next(new ErrorHander("Invalid Email & Password",401))
        }

        const isPasswordMatched = await user.comparePassword(password);

        if(!isPasswordMatched){
            next(new ErrorHander("Invalid Password",401))
        }

        else{
           sendToken(user,200,res)
        }
     

})
// Testing Login API =



//Logout User

exports.logoutUser= catchAsyncError(async(req,res,next)=>{

        res.cookie("token",null,{
            expires : new Date(Date.now()),
            httpOnly:true
        })

        res.status(200).json({
            success:true,
            message:"Logged Out!"
        })
})

// Testing Logout User API



//forgot Password

exports.forgotPassword = catchAsyncError(async(req,res,next)=>{

    const user = await User.findOne({email:req.body.email});

        if(!user){

           return next( new ErrorHander("Account Does not exists !! please Enter Valid Email",404))

        }
        // get resetToken Password

       const resetToken =  user.getResetPasswordToken();
       
       await user.save({validateBeforeSave:false});

       //creating link to send user to reset password
       
       const resetPasswordUrl = `${req.protocol}://${req.host}/api/v1/password/reset/${resetToken}`

       const message = `Your Reset Password Link is :- \n \n ${resetPasswordUrl} \n\n If you have not requested it then ignore`

   
    try {

        await sendEmail({

            email:user.email,
            subject: `Kilvish.com Password Recovery `,
            message

        })

        res.status(200).json({
            success:true ,
            message: `email sent to ${user.email} successfully !`
        })
       
    } catch (error) {
        user.resetPasswordToken = undefined ;
        user.resetPasswordExpire = undefined;

        await user.save({validateBeforeSave:false});

        return next(new ErrorHander(error.message))
    }


})

//Forgot Password API - sent link to email




//reset password after sending link

exports.resetPassword = catchAsyncError(async (req,res,next)=>{

    const resetPasswordToken = crypto.createHash("sha256").update(req.params.token).digest("hex");

        const user = await User.findOne({ resetPasswordToken, resetPasswordExpire:{$gt : Date.now()}})

        if(!user){
            return next(new ErrorHander("Reset Link is Invalid or Expired Please Request Again",400));
        }

        if(req.body.password !== req.body.confirmPassword){
            return next(new ErrorHander("Password Mismached !",400));
        }

    user.password = req.body.password;

    user.resetPasswordToken = undefined ;
    user.resetPasswordExpire = undefined;

    await user.save()

    sendToken(user,200,res);

})
//After Receiving Link on Email - reset testing is below but here link is expire



//View User Details - by user

  exports.getUserDetails =  catchAsyncError(async (req,res,next)=>{

    const user = await User.findById(req.user.id)

        res.status(200).json({
            success:true,
            user
        })
  })

//Tesing view User Details -by user




  //Change/Update Password  

  exports.updatePassword = catchAsyncError(async (req,res,next)=>{

    const user =await User.findById(req.user.id).select("+password") ;

    const isPasswordMatched = await user.comparePassword(req.body.oldPassword);

    if(!isPasswordMatched){
        next(new ErrorHander("Invalid OldPassword",401))
    }

    if(req.body.newPassword !== req.body.confirmPassword){
        return next(new ErrorHander("Password Mismached !",400));
    }


    user.password = req.body.confirmPassword ;

    await user.save();

    sendToken(user,200,res);


  })

//==========Testing Change Password API ==========






    // Update User profile

    exports.updateProfile = catchAsyncError(async (req,res,next)=>{

         const newUserData= {
            nameL: req.body.name,
            email:req.body.email,
         }
         console.log(req.user.id);
         console.log(newUserData);

         const user = await User.findByIdAndUpdate(req.user.id, newUserData,{
            new:true,
            runValidators :true,
            useFindandModify:false
         })

         console.log(user)
        res.status(200).json({
            success:true,
            user
        })
   
   
      })
//get all users (admin)

exports.getAllUser = catchAsyncError(async (req,res,next)=>{

        const users = await User.find();

        res.status(200).json({
            success:true,
            users
        })
})

//get Single User (admin)

exports.getSingleUser = catchAsyncError(async (req,res,next)=>{

    const user = await User.findById(req.params.id)


        if(!user){
            return next(new ErrorHander("User Not Found ! ",400))
        }
        else {
            res.status(200).json({
                success:true,
                user
            })
        }
           
       
   
})

//Get Single user - admin Testing - but here user is login



 // Update User's Role - Admin
 exports.updateUserRole = catchAsyncError(async (req,res,next)=>{

    const newUserData= {
       email:req.body.email,
       role: req.body.role
    }
    console.log(req.user.id);
    console.log(newUserData);

    const user = await User.findByIdAndUpdate(req.params.id, newUserData,{
       new:true,
       runValidators :true,
       useFindandModify:false
    })

    console.log(user)
   res.status(200).json({
       success:true,
       user
   })


 })

//=========Testing APi - Update user's role to admin ----



  // Delete User - Admin

  exports.deleteUser = catchAsyncError(async (req,res,next)=>{

   
    const user = await User.findById(req.params.id)

    if(!user){
        return next( new ErrorHander("User not found",400))
    }
   
    user.remove();

    console.log(user)
   res.status(200).json({
       success:true,
       message:"User Deleted Successfully !!"
   })


 })

===========Tesing Api - Delete user - Only Admin can do this -





============Create user router == UserRoute.js  is below  ====================

const express = require("express");
const { registerUser,
     loginUser,
     logoutUser,
     forgotPassword,
    resetPassword,
     getUserDetails,
    updatePassword,
     updateProfile,
      getAllUser,
      getSingleUser,
      updateUserRole,
      deleteUser
     } = require("../controllers/userController");
const router = express.Router();

const { isAuthenticatedUser, authorizeRoles } = require('../middleware/auth.js');

router.route("/register").post(registerUser)

router.route("/login").post(loginUser)

router.route("/password/forgot").post(forgotPassword)

router.route("/password/reset/:token").put(resetPassword)

router.route('/logout').get(logoutUser)

router.route('/me').get(isAuthenticatedUser ,getUserDetails)

router.route('/password/update').put(isAuthenticatedUser, updatePassword)

router.route('/me/update').put(isAuthenticatedUser, updateProfile)

router.route('/admin/users').get(isAuthenticatedUser,authorizeRoles("admin"),getAllUser)

router.route('/admin/user/:id').get(isAuthenticatedUser,authorizeRoles("admin"), getSingleUser)

router.route('/admin/user/:id').put(isAuthenticatedUser,authorizeRoles("admin"), updateUserRole)

router.route('/admin/user/:id').delete(isAuthenticatedUser,authorizeRoles("admin"), deleteUser)



module.exports = router;







==================End===============

Comments