Skip to content

Commit

Permalink
backend ready for sending password reset link in mail
Browse files Browse the repository at this point in the history
  • Loading branch information
JaberHPranto committed Jul 8, 2021
1 parent 72dd65c commit 217b8c7
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 2 deletions.
3 changes: 3 additions & 0 deletions client/src/components/Ecommerce/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import { Container, Nav, Navbar, NavDropdown } from 'react-bootstrap'
import { useDispatch, useSelector } from 'react-redux'
import { LinkContainer } from 'react-router-bootstrap'
import { useHistory } from 'react-router-dom'
import { logout } from '../../redux/actions/userActions'
import SearchBox from './SearchBox'
import { toastErrorMessage } from './ToastMessage'
Expand All @@ -10,9 +11,11 @@ import { toastErrorMessage } from './ToastMessage'
function Header() {
const { userInfo } = useSelector(state => state.userLogin)
const dispatch = useDispatch()
const history = useHistory()

const handleLogout = () => {
dispatch(logout())
history.push("/")
toastErrorMessage("You're logged out")
}

Expand Down
1 change: 1 addition & 0 deletions client/src/constants/cartConstants.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const CART_ADD_ITEM = 'CART_ADD_ITEM'
export const CART_REMOVE_ITEM = 'CART_REMOVE_ITEM'
export const CART_RESET = 'CART_RESET'
8 changes: 7 additions & 1 deletion client/src/redux/reducers/cartReducers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CART_ADD_ITEM, CART_REMOVE_ITEM } from '../../constants/cartConstants';
import { CART_ADD_ITEM, CART_REMOVE_ITEM, CART_RESET } from '../../constants/cartConstants';

export const cartReducer = (state = { cartItems: [] }, action) => {
switch (action.type) {
Expand All @@ -24,6 +24,12 @@ export const cartReducer = (state = { cartItems: [] }, action) => {
...state,
cartItems: state.cartItems.filter(p=>p.productId !== action.payload)
}

case CART_RESET:
return {
...state,
cartItems:[]
}

default:
return state
Expand Down
79 changes: 79 additions & 0 deletions server/controller/userController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import bcrypt from 'bcrypt';
import crypto from 'crypto';
import asyncHandler from 'express-async-handler';
import jwt from 'jsonwebtoken';
import User from '../models/userModel.js';
import { sendEmail } from '../utils/sendEmail.js';


// @ User Login
Expand Down Expand Up @@ -101,3 +103,80 @@ export const updateUserProfile = asyncHandler(async (req, res) => {

})



// @ forget password
export const forgetPassword = async (req, res) => {
const { email } = req.body

try {
const user = await User.findOne({ email })
if (!user)
return res.status(404).json({error:"User doesn't exist"})

const resetToken = user.getPasswordResetToken()


// user.resetPasswordToken = user.resetPasswordToken
// user.resetPasswordExpire = user.resetPasswordExpire
await user.save()

const resetUrl = `http://localhost:3000/forget-password/${resetToken}`
const message = `
<h1> Plant Land </h1>
<h2>You have requested a password reset</h2>
<p>Please go to this link to reset your password</p>
<a href=${resetUrl} clicktracking=off>${resetUrl}</a>
`
// sending mail
try {
await sendEmail({
to: user.email,
subject: 'Password Reset Request',
text: message
})
res.status(200).json({ message: 'Success',data:"Email Sent" ,resetToken})
} catch (error) {
user.resetPasswordToken = undefined
user.resetPasswordExpire = undefined

await user.save()
console.log(error);
res.status(500).json("Failed to send email")
}

res.status(200).json({ message: 'Success',data:"Email Sent"})


} catch (error) {
console.log(error);
res.status(404).json({ error: "Forget password failed" })
}
}

// @ reset password
export const resetPassword = async (req, res) => {
try {
const resetPasswordToken = crypto.createHash('sha256').update(req.params.resetToken).digest('hex')
const user = await User.findOne({
resetPasswordToken,
resetPasswordExpire: { $gt: Date.now() }
})

if (!user) {
return res.status(400).json({ error: "Invalid Reset Token" })
}

user.password = req.body.password
user.resetPasswordToken = undefined
user.resetPasswordExpire = undefined

await user.save()

res.status(200).json({success:true,data:'Password reset success'})

} catch (error) {
console.log(error);
res.status(500).json({ error: "Failed to reset password" })
}
}
15 changes: 15 additions & 0 deletions server/models/userModel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import bcrypt from 'bcrypt'
import crypto from 'crypto'
import mongoose from 'mongoose'

const userSchema = mongoose.Schema({
Expand All @@ -20,6 +21,8 @@ const userSchema = mongoose.Schema({
required: true,
default:false
},
resetPasswordToken: String,
resetPasswordExpire: Date
}, {
timestamps:true
})
Expand All @@ -34,5 +37,17 @@ userSchema.pre('save', async function (next) {
this.password = await bcrypt.hash(this.password,salt)
})

// method for forget password
userSchema.methods.getPasswordResetToken = function () {
const resetToken = crypto.randomBytes(20).toString('hex')

// setting a field in user model
this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex')
this.resetPasswordExpire = Date.now() + 10 * (60 * 1000)

return resetToken

}

const User = mongoose.model("User", userSchema)
export default User
5 changes: 5 additions & 0 deletions server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.13.0",
"morgan": "^1.10.0",
"nodemailer": "^6.6.2",
"nodemon": "^2.0.8"
}
}
5 changes: 4 additions & 1 deletion server/routes/userRoutes.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import express from 'express'
import { authUser, getUserProfile, registerUser, updateUserProfile } from '../controller/userController.js'
import { authUser, forgetPassword, getUserProfile, registerUser, resetPassword, updateUserProfile } from '../controller/userController.js'
import { isLoggedIn } from '../middlewares/authMiddleware.js'

const router = express.Router()

router.post("/login", authUser)
router.post("/register",registerUser)
router.route("/profile").get(isLoggedIn, getUserProfile).put(isLoggedIn, updateUserProfile)
router.post("/forget-password", forgetPassword)
router.put("/reset-password/:resetToken",resetPassword)



export default router
26 changes: 26 additions & 0 deletions server/utils/sendEmail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import nodemailer from 'nodemailer'

export const sendEmail = (options) => {
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL_NAME,
pass: process.env.EMAIL_PASS

},
})

const mailOptions = {
from: process.env.EMAIL_NAME,
to: options.to,
subject: options.subject,
html: options.text
}

transporter.sendMail(mailOptions, function (err, info) {
if (err) {
console.log(err);
}else console.log(info);
})
}

0 comments on commit 217b8c7

Please sign in to comment.