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

Popular posts from this blog

Part 19- Router (Networking Devices)- Computer Networking- CCNA

Hello friends...i am Vasu Birla and today will discuss about the most important Networking Device ..Router.  so let's start... ROUTER Router is a device which connect two or more networks together, which is why router is also known is Inter-networking device also. Inter-networking means two or more networks are connected together with the help of router. one more thing router is just like a computer  but it is designed for routing only, our computer can be router also but that are software router while hardware router which are specialize for routing is more efficient and fast than software router.  There is a Operating System installed on router which get moves data from one network to another network with the help of routing table.  Router does work on Network layer or Layer 3 of the OSI model.  Cisco Router There many companies which manufacture Router but main companies are - Cisco , Juniper , HP, 3com and Nortel  ...

How to deploy NodeJS app on server with Apache2 and acess it with Server IP addresss - Node JS deploy project Live.

     hello friens , This is Vasu Birla , in previous post we have seen the deployement of NodeJS app on AWS instance server instance but AWS server is expensive than other servers . SO today we will use simple Ubuntu server for making Live out Project using Apache2 . At the end you will be abe to access your NodeJS app using server IP address from anywhere  .. 1.  Login to your server using SSH terminal . (in AWS part i already explained how to do this )     -> Open your putty in hostname put your server IP -      login with ssh username ->root and password     (if you dont have root username and pass ask your      provider or reset it from cpanel or hosting panel ) 2. after login - on terminal you can Put your project anywhere.     There are two ways to put your project folder on server location     (i) - > using Github - (very popular and easy to track your everyday code changes t...

GitHub Repo Collaboration Work on single project

 =============================================== To collaborate effectively with your friend on the same project, you should use Git branches to manage different lines of development. Here's a step-by-step procedure you can follow to streamline collaboration: 1. Create Separate Branches for Each Developer Create a New Branch for Your Friend: On your local repository, create a new branch for your friend. For example if your friend name is kilvish , if you want to create a branch named kilvish , you would run: make sure you would be on main branch already   command->  git checkout -b kilvish git push origin kilvish 2. Set Up Your Friend’s Environment( On your Friend's System )  at kilvish side  run ->  Clone the Repository (if not already done): If your friend hasn’t cloned the repository yet, they should do so: command ->  git clone https://github.com/Vasu-Birla/your-repo.git   // your your main clone line  Fetch All Bran...