Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error handling in email.js #194

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 4-natours/starter/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": ["airbnb", "prettier", "plugin:node/recommended"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
// "prettier/prettier": "error",
"spaced-comment": "off",
"no-console": "warn",
"consistent-return": "off",
Expand Down
1 change: 1 addition & 0 deletions 4-natours/starter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
1 change: 1 addition & 0 deletions 4-natours/starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# NodeJS_With_Jonas
81 changes: 81 additions & 0 deletions 4-natours/starter/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const express = require('express');
const fs = require('fs');
const morgan = require('morgan');

const app = express();
const AppError = require('./utils/appError');
const globalErrorHandler = require('./controllers/errorController')
const tourRouter = require('./routes/tourRoutes')
const userRouter = require('./routes/userRoutes');

//This is a middle-ware it will in the middle of req and res.

console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}


app.use(express.json());
// This will a simple route system to get their..
app.use(express.static(`${__dirname}/public`))

// app.get('/', (req, res) => {
// res.status(200).json({
// firstName: "Soumya",
// middleName: "Subhrajit",
// lastName: "bag",
// age: 20
// })
// })

// if (!tour) {
// return res.status(404).json({
// status: 'fail',
// message: "Invalid ID"
// })
// }



// Global-Middle-ware....
/*
app.use((req, res, next) => {
console.log("Hi, from the middle-ware.");
req.requestTime = new Date().toISOString();
next();
})
*/

//////////////////////////////////////
// old style of doing routes..

// app.get('/api/v1/tours', getAllTours)
// app.get('/api/v1/tours/:id', getTours)
// // Create a tour..
// app.post('/api/v1/tours', createTours)
// // Update the DB....
// app.patch('/api/v1/tours/:id', updateTours)
// // Delete id from the DB....
// app.delete('/api/v1/tours/:id', deleteTours)

/////////////////////////////////////////////////


// Mounting using middle-wire..
app.use('/api/v1/tours', tourRouter);
app.use('/api/v1/users', userRouter);



app.all('*', (req, res, next) => {

// It have the 2 parameter one for the message and another one for the statusCode...
next(new AppError(`Can't find the ${req.originalUrl} rout in the server!`))
})


// GLOBAL ERROR HANDLING MIDDLEWARE.
app.use(globalErrorHandler)

module.exports = app;
13 changes: 13 additions & 0 deletions 4-natours/starter/config.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

# development
NODE_ENV = development
USER_NAME = Soumya
DATABASE = mongodb+srv://soumyasubhrajit:<password>@cluster0.unkx990.mongodb.net/footpathfinders?retryWrites=true&w=majority
DATABASE_PASSWARD = kanha456
JWT_SECERT = this-is-my-secert-key-that-am-never-goona-show-to-you
JWT_EXPIRES_IN = 90d

EMAIL_USERNAME=5a64213903a459
EMAIL_PASSWORD=9501fec9e11b1f
EMAIL_HOST=smtp.mailtrap.io
EMAIL_PORT=25
202 changes: 202 additions & 0 deletions 4-natours/starter/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/* eslint-disable no-unused-expressions */
// THIS IS FOR THE CREATING A USER...
const User = require('../models/userModel');
const catchAsync = require('../utils/catchAsync');
const jwt = require('jsonwebtoken');
const AppError = require('../utils/appError');
const { promisify } = require('util')
const sendEmail = require('../utils/email')
const crypto = require('crypto');

// GENATATING A TOEKN;
const signToken = id => jwt.sign({ id }, process.env.JWT_SECERT, { expiresIn: process.env.JWT_EXPIRES_IN });


// SNEDING A TOKEN..
const createSendToken = (user, statusCode, res) => {
const token = signToken(user._id);

res.status(201).json({
status: "Success",
token,
data: {
user
}
})
}

exports.signup = catchAsync(async (req, res, next) => {
const newUser = await User.create({
name: req.body.name,
email: req.body.email,
password: req.body.password,
passwordConfirm: req.body.passwordConfirm
})
createSendToken(newUser, 201, res);

});






exports.login = catchAsync(async (req, res, next) => {
const { email, password } = req.body;


// 1) CHECK IS THE MAIL AND PASSWORD EXIST..
if (!email || !password) {
return next(new AppError('Please provide email & password', 400))
}

// CHECK IF THE USER EXISTS AND PASSWORD EXIST OR NOT..
// 2) Check if user exists && password is correct
const user = await User.findOne({ email }).select('+password');

console.log(user);

if (!user || !(await user.correctPassword(password, user.password))) {
return next(new AppError('Incorrect email or password', 401));
}

// IF EVEYTHING IS FINE THEN SEND THE TOKEN TO USER...

createSendToken(user, 200, res)
})

exports.protect = catchAsync(async (req, res, next) => {
// 1) Getting token and check of it's there..
// eslint-disable-next-line no-shadow
let token;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
token = req.headers.authorization.split(' ')[1]
}
console.log(token);

if (!token) {
return next(new AppError('You are not logged in!, Please logged in to get the access', 401))
}

// 2) varificatin of the token..
const decode = await promisify(jwt.verify)(token, process.env.JWT_SECERT)

// 3) check is user still exists..
const freshUser = await User.findById(decode.id);
if (!freshUser) {
return next(new AppError('The user belonging to this token does not exist!', 401))
}

// 4) checks is user changed password after the token was issued..

if (freshUser.changePasswordAfter(decode.id)) {
return next(new Error('User recently changed password: Please log in again.', 401))
}

// GRANT ACCESS TO PROTECTED ROUTE..
req.user = freshUser;

next();
})

exports.restrictTo = (...roles) => (req, res, next) => {
if (!roles.includes(req.user.role)) {
return next(new AppError('You don not have permission to perform this action!!', 403))
}

next();
}

// REST ADD FORGET SEETING OF THE PASSWORDS..

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

// GET USER BASED ON POSTED EMAIL..
const user = await User.findOne({ email: req.body.email })
if (!user) {
return next(new AppError('There is no user with this email address!!', 404))
}

// GENERATING THE RANDOM TOKEN.....
const resetToken = user.createPasswordReset();

await user.save({ validateBeforeSave: false })


// SENDING THE EMAIL..
const restURL = `${req.protocol}://${req.get('host')}/api/v1/users/resetPassword/${resetToken}`

const message = `Forgot your password? Sumbit a PATCH request with your new password and passwordConfirm to: ${restURL}.\nIf you didn't forget you password, please ignore this email`


try {
const data = await sendEmail({
email: user.email,
subject: 'Your password reset (valid for 10 min)',
message
})
console.log(data);
res.status(200).json({
status: 'success',
message: 'Token sent to email'
})
} catch (err) {
user.passwordResetToken = undefined
user.passwordResetExpires = undefined
await user.save({ validateBeforeSave: false })

return next(new AppError('There was an error sending the email, Try again later!', 500))
}
})

// reset the password..


exports.resetPassword = catchAsync(async (req, res, next) => {
// 1) Get user based on the token
const hashedToken = crypto
.createHash('sha256')
.update(req.params.token)
.digest('hex');

const user = await User.findOne({
passwordResetToken: hashedToken,
passwordResetExpires: { $gt: Date.now() }
});


// 2) If token has not expired, and there is user, set the new password
if (!user) {
return next(new AppError('Token is invalid or has expired', 400));
}
user.password = req.body.password;
user.passwordConfirm = req.body.passwordConfirm;
user.passwordResetToken = undefined;
user.passwordResetExpires = undefined;
await user.save();

// 3) Update changedPasswordAt property for the user
// 4) Log the user in, send JWT
createSendToken(user, 200, res);

});


exports.updatePassword = async (req, res, next) => {
// 1) Get user from collection..
const user = await User.findById(req.user.id).select('+password')
console.log(user);

// 2)
if (!(await user.createPasswordReset(req.body.passwordCurrent, user.password))) {
return next(new AppError('Your current password is worng', 401))
}

// 3) If password is correct then update the password..
user.password = req.body.password;
user.passwordConfirm = req.body.passwordConfirm;
await user.save();

// 4) Log user in , send a token;
createSendToken(user, 200, res);
}
77 changes: 77 additions & 0 deletions 4-natours/starter/controllers/errorController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const AppError = require('../utils/appError')

// handling the incoming the errors..

const handleCastErrorDB = err => {
const message = `Invalid ${err.path}: ${err.value}.`;
return new AppError(message, 400);
};

const handleDuplicateFieldsDB = err => {
const value = err.errmsg.match(/(["'])(\\?.)*?\1/)[0];
console.log(value);
}

const sendErrorDev = function (err, res) {
res.status(err.statusCode).json({
status: err.status,
message: err.message,
err: err,
stac: err.stack
})
}
const handleValidationErrorDB = err => {
const errors = Object.values(err.errors).map(el => el.message);

const message = `Invalid input data. ${errors.join('. ')}`;
return new AppError(message, 400);
};


const sendErrorProd = function (err, res) {
if (err.isOperational) {
res.status(err.statusCode).json({
status: err.status,
message: err.message
})
} else {
console.log('Error: 💥', err);
res.status(500).json({
status: 'error',
message: 'Somthing went wrong!'
})
}
}

//////////////////////////////////////////////
// HANDLE ERROR OF USERS..

const handleJWTError = err => {
console.log("Why are you guy!");
return new AppError('Invalid token, please log in again!', 401)
}

const handleJWTExpired = err => new AppError('Your token has expired! please log in again!', 401)


module.exports = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error'

if (process.env.NODE_ENV === 'development') {
//Do the dev error
sendErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {

let error = { ...err };
if (error.name === 'CastError') error = handleCastErrorDB(error);
if (error.code === 11000) error = handleDuplicateFieldsDB(error);
if (error === 'validationError')
error = handleValidationErrorDB(error)
if (error.name === 'JsonWebTokenError') error = handleJWTError()
if (error.name === 'TokenExpiredError') error = handleJWTExpired()

// Do the prodcution error.
sendErrorProd(error, res)
}
}
1 change: 1 addition & 0 deletions 4-natours/starter/controllers/tempCodeRunnerFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
password
Loading