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 15- What is Repeater (Networking Devices)- Computer Networking- CCNA

Repeater  hello friends i am Vasu Birla and today i am starting new segment of CCNA computer networking  its a Networking Devices. we will discuss every important Devices used in networks. Repeater is a first networking devices. What is Repeater  Repeater is a device that receives signals and re-transmits by amplifying or regenerating signals. Repeater has two port one is for receive signals from previous network and second port is for retransmit signals to the next extended network. Two Port Repeater Repeater is a device which is used to Regenerate or replicate signal (Pichhe se aa rahe signal ko regenerate karke ya amplify karke aage strong signals bhej sakte he) Analog and digital both type of signals can be retransmitted by repeater. Here there is difference between regeneration and amplifying.  Amplification means , received signals will be amplified as it is , whether there are impurities in signals  and Regeneration means repeate...

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...

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...