Register new User, Login User, Delete user, Update User Profile , Forgot/Reset password, Change Password - Node Js , MERN Stack Post 101
========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
Post a Comment