make it betterl

This commit is contained in:
pawan-dot 2022-06-20 18:46:22 +05:30
parent bb0e9f4213
commit 42c9bdf74f
17 changed files with 400 additions and 133 deletions

25
Utils/errorhander.js Normal file
View File

@ -0,0 +1,25 @@
class ErrorHander extends Error {
constructor(message, status) {
// Calling parent constructor of base Error class.
super(message);
// Saving class name in the property of our custom error as a shortcut.
this.name = this.constructor.name;
// Capturing stack trace, excluding constructor call from it
// (this is probably no longer required in node >=8, see the comments)
Error.captureStackTrace(this, this.constructor);
// You can use any additional properties you want.
// I'm going to use preferred HTTP status for this error types.
// `500` is the default value if not specified.
this.status = status || 500;
}
};
//module.exports = ErrorHander
export default ErrorHander;

27
Utils/sendEmail.js Normal file
View File

@ -0,0 +1,27 @@
import nodeMailer from "nodemailer"
const sendEmail = async (options) => {
const transporter = nodeMailer.createTransport({
host: process.env.SMPT_HOST,
port: process.env.SMPT_PORT,
service: process.env.SMPT_SERVICE,
auth: {
user: process.env.SMPT_MAIL,
pass: process.env.SMPT_PASSWORD,
},
});
// console.log(process.env.SMPT_PORT)
// console.log(process.env.SMPT_MAIL)
// console.log(process.env.SMPT_PASSWORD)
//console.log(transporter)
const mailOptions = {
from: process.env.SMPT_MAIL,
to: options.email,
subject: options.subject,
text: options.message,
};
await transporter.sendMail(mailOptions);
};
export default sendEmail;

2
app.js
View File

@ -24,7 +24,7 @@ app.use(fileUpload({
//auth
import user from "./routes/userRoute.js"
app.use("/api", user);
app.use("/api/v1/", user);
//category
import category from "./routes/categoryRoute.js"
app.use("/api", category);

View File

@ -1,57 +1,55 @@
//require("dotenv").config({ path: "backend/config/config.env" });
import ErrorHander from "../utils/errorhander.js"
import catchAsyncErrors from "../middlewares/catchAsyncErrors.js"
import User from "../models/userModel.js"
import sendToken from "../Utils/jwtToken.js"
import sendToken from "../utils/jwtToken.js"
import sendEmail from "../utils/sendEmail.js"
import crypto from "crypto"
import cloudinary from "cloudinary"
// 1.Register a User
export const registerUser = async (req, res) => {
try {
const { name, email, password, confirmPassword } = req.body;
// console.log(name)
if (password !== confirmPassword) {
res.status(401).json({ msg: "Password not Match!!" })
}
export const registerUser = catchAsyncErrors(async (req, res, next) => {
const files = req.files.avatar;
const myCloud = await cloudinary.uploader.upload(files.tempFilePath, {
folder: "cmp-user/image",
},
function (error, result) { (result, error) });
const { name, email, password, phone } = req.body;
const user = await User.create({
name,
email,
password
password,
phone,
avatar: {
public_id: myCloud.public_id,
url: myCloud.secure_url,
},
});
// const token = user.getJWTToken();
// // console.log(token)
// res.status(201).json({
// success: true,
// token,
// })
sendToken(user, 201, res);
} catch (error) {
console.log(error)
res.status(500).json({
success: false,
msg: "Failled to register !!"
});
}
};
// 2.Login User
export const loginUser = async (req, res) => {
try {
export const loginUser = catchAsyncErrors(async (req, res, next) => {
const { email, password } = req.body;
// checking if user has given password and email both
if (!email || !password) {
res.status(400).json({ msg: "Please Enter Email & Password" })
return next(new ErrorHander("Please Enter Email & Password", 400));
}
const user = await User.findOne({ email }).select("+password");
if (!user) {
res.status(401).json({ msg: "Invalid email or password" })
return next(new ErrorHander("Invalid email or password", 401));
}
const isPasswordMatched = await user.comparePassword(password);
if (!isPasswordMatched) {
res.status(401).json({ msg: "Invalid email or password" })
return next(new ErrorHander("Invalid email or password", 401));
}
// const token = user.getJWTToken();
// res.status(201).json({
@ -59,19 +57,11 @@ export const loginUser = async (req, res) => {
// token,
// })
sendToken(user, 200, res);
} catch (error) {
res.status(500).json({
success: false,
msg: "Failled to Login !!"
});
}
};
// 3.Logout User
export const logout = async (req, res) => {
try {
export const logout = catchAsyncErrors(async (req, res, next) => {
res.cookie("token", null, {
expires: new Date(Date.now()),
httpOnly: true,
@ -81,37 +71,113 @@ export const logout = async (req, res) => {
success: true,
message: "Logged Out",
});
} catch (error) {
res.status(500).json({
success: false,
msg: "Failled to logOut !!"
});
// 4.Forgot Password
export const forgotPassword = catchAsyncErrors(async (req, res, next) => {
const user = await User.findOne({ email: req.body.email });
if (!user) {
return next(new ErrorHander("User not found", 404));
}
// Get ResetPassword Token
const resetToken = user.getResetPasswordToken();//call function
//save database reset token
await user.save({ validateBeforeSave: false });
//create link for send mail
// const resetPasswordUrl = `http://localhost:5000/api/v1/user/password/reset/${resetToken}` //send from localhost
//send from anyhost
const resetPasswordUrl = `${req.protocol}://${req.get(
"host"
)}/api/v1/user/password/reset/${resetToken}`;
//const resetPasswordUrl = `${process.env.FRONTEND_URL}:/api/user/password/reset/${resetToken}`;
//const resetPasswordUrl = `${process.env.FRONTEND_URL}/password/reset/${resetToken}`;
};
const message = `Your password reset token are :- \n\n ${resetPasswordUrl} \n\nIf you have not requested this email then, please ignore it.`;
// 4.update User password
export const updatePassword = async (req, res) => {
try {
// console.log("fhrbhebhgbfr")
// console.log(req.user._id)
if (!req.user) {
return res.status(400).json({ message: 'User Not Found' });
await sendEmail({
email: user.email,
subject: `CMP 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, 500));
}
const user = await User.findById(req.user._id).select("+password");
});
// 5.Reset Password
export const resetPassword = catchAsyncErrors(async (req, res, next) => {
// creating token hash
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 Password Token is invalid or has been expired",
400
)
);
}
//replace previous password
if (req.body.password !== req.body.confirmPassword) {
return next(new ErrorHander("Password does not password", 400));
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save();
sendToken(user, 200, res);
});
//6.Get User Detail
export const getUserDetails = catchAsyncErrors(async (req, res, next) => {
const user = await User.findById(req.user.id);
res.status(200).json({
success: true,
user,
});
});
// 7.update User password
export const updatePassword = catchAsyncErrors(async (req, res, next) => {
const user = await User.findById(req.user.id).select("+password");
const isPasswordMatched = await user.comparePassword(req.body.oldPassword);
if (!isPasswordMatched) {
res.status(400).json({ msg: "Old password is incorrect" })
return next(new ErrorHander("Old password is incorrect", 400));
}
if (req.body.newPassword !== req.body.confirmPassword) {
res.status(400).json({ msg: "password does not match" })
return next(new ErrorHander("password does not match", 400));
}
user.password = req.body.newPassword;
@ -119,11 +185,43 @@ export const updatePassword = async (req, res) => {
await user.save();
sendToken(user, 200, res);
} catch (error) {
// console.log(error)
res.status(500).json({
success: false,
msg: "Failled to Password Change !!"
});
// 8.update User Profile
export const updateProfile = catchAsyncErrors(async (req, res, next) => {
const newUserData = {
name: req.body.name,
phone: req.body.phone,
email: req.body.email,
};
if (req.files) {
const files = req.files.avatar;
const user = await User.findById(req.user.id);
const imageId = user.avatar.public_id;
await cloudinary.uploader.destroy(imageId)
const myCloud = await cloudinary.uploader.upload(files.tempFilePath, {
folder: "image",
},
function (error, result) { (result, error) });
newUserData.avatar = {
public_id: myCloud.public_id,
url: myCloud.secure_url,
};
}
}
const user = await User.findByIdAndUpdate(req.user.id, newUserData, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
user
});
});

View File

@ -1,14 +1,16 @@
import User from "../models/userModel.js";
import jwt from "jsonwebtoken";
import ErrorHander from "../utils/errorhander.js"
export const isAuthenticated = async (req, res, next) => {
export const isAuthenticatedUser = async (req, res, next) => {
try {
// const { token } = req.cookies;
const getToken = req.headers;
const { token } = req.cookies;
//const getToken = req.headers;
// // console.log(getToken.authorization)
// console.log(token)
// //remove Bearer from token
const token = getToken.authorization.slice(7);
// const token = getToken.authorization.slice(7);
// // console.log(token)
if (!token) {
@ -33,3 +35,17 @@ export const isAuthenticated = async (req, res, next) => {
});
}
};
export const authorizeRoles = (...roles) => {//pass admin
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return next(
new ErrorHander(
`Role: ${req.user.role} is not allowed to access this resouce `,
403
)
);
}
next();
};
};

View File

@ -0,0 +1,3 @@
export default (theFunc) => (req, res, next) => {
Promise.resolve(theFunc(req, res, next)).catch(next);//prebuild javascript class// basicaly try catch
};

36
middlewares/error.js Normal file
View File

@ -0,0 +1,36 @@
import ErrorHandler from "../utils/errorhander.js";
module.exports = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.message = err.message || "Internal Server Error";
// Wrong Mongodb Id error(castError)
if (err.name === "CastError") {
const message = `Resource not found. Invalid: ${err.path}`;
err = new ErrorHandler(message, 400);
}
// Mongoose duplicate key error
if (err.code === 11000) {
const message = `Duplicate ${Object.keys(err.keyValue)} Entered`;
err = new ErrorHandler(message, 400);
}
// Wrong JWT error
if (err.name === "JsonWebTokenError") {
const message = `Json Web Token is invalid, Try again `;
err = new ErrorHandler(message, 400);
}
// JWT EXPIRE error
if (err.name === "TokenExpiredError") {
const message = `Json Web Token is Expired, Try again `;
err = new ErrorHandler(message, 400);
}
res.status(err.statusCode).json({
success: false,
//err: err.stack //full location of error
message: err.message,
})
}

View File

@ -1,3 +1,5 @@
import dotenv from 'dotenv'
dotenv.config()
import mongoose from "mongoose"
import validator from "validator"
import bcrypt from "bcryptjs"
@ -9,7 +11,7 @@ const userSchema = new mongoose.Schema({
type: String,
required: [true, "Please Enter Your Name"],
maxLength: [30, "Name cannot exceed 30 characters"],
minLength: [3, "Name should have more than 4 characters"],
minLength: [4, "Name should have more than 4 characters"],
},
email: {
type: String,
@ -17,15 +19,40 @@ const userSchema = new mongoose.Schema({
unique: true,
validate: [validator.isEmail, "Please Enter a valid Email"],
},
phone: {
type: Number,
required: [true, "Please Enter Your phone no."],
maxLength: [12, "phone cannot exceed 12 characters"],
minLength: [6, "phone should have more than 6 characters"],
},
password: {
type: String,
required: [true, "Please Enter Your Password"],
minLength: [4, "Password should be greater than 8 characters"],
minLength: [6, "Password should be greater than 6 characters"],
select: false,//find not got passpord
},
avatar: {
public_id: {
type: String,
required: true,
},
url: {
type: String,
required: true,
},
},
role: {
type: String,
default: "user",
},
// createdAt: {
// type: Date,
// default: Date.now,
// },
}, { timestamps: true }
);
resetPasswordToken: String,
resetPasswordExpire: Date,
}, { timestamps: true });
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
@ -41,12 +68,30 @@ userSchema.methods.getJWTToken = function () {
expiresIn: "1d",
});
};
//process.env.JWT_SECRET
// console.log(process.env.JWT_SECRET)
// Compare Password
userSchema.methods.comparePassword = async function (password) {
return await bcrypt.compare(password, this.password);
};
// Generating Reset Token
userSchema.methods.getResetPasswordToken = function () {
// Generating Token
const resetToken = crypto.randomBytes(20).toString("hex");
// Hashing and adding reset PasswordToken to userSchema
this.resetPasswordToken = crypto
.createHash("sha256")
.update(resetToken)
.digest("hex");
//expire password time
// console.log(this.resetPasswordToken)
this.resetPasswordExpire = Date.now() + 15 * 60 * 1000;//15 minut
return resetToken;
};
const UserModel = mongoose.model("User", userSchema);
export default UserModel;

14
package-lock.json generated
View File

@ -20,6 +20,7 @@
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.3.5",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.7.5",
"validator": "^13.7.0"
}
},
@ -1251,6 +1252,14 @@
"node": ">= 0.4.0"
}
},
"node_modules/nodemailer": {
"version": "6.7.5",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz",
"integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -2820,6 +2829,11 @@
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
"optional": true
},
"nodemailer": {
"version": "6.7.5",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz",
"integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",

View File

@ -22,6 +22,7 @@
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.3.5",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.7.5",
"validator": "^13.7.0"
}
}

View File

@ -7,7 +7,7 @@ import {
getOneDirectory
} from "../controllers/directoryController.js"
const router = express.Router();
import { isAuthenticated } from "../middlewares/auth.js"
import { isAuthenticatedUser } from "../middlewares/auth.js"
router.route("/directory/create/").post(createDirectory)
router.route("/directory/getAll/").get(getAllDirectory)
router.route("/directory/getOne/:id").get(getOneDirectory)

View File

@ -1,31 +1,33 @@
import express from "express";
// import isAuthenticated from "../Utils/aurhe";
import express from "express"
import {
registerUser,
loginUser,
logout,
updatePassword
forgotPassword,
resetPassword,
getUserDetails,
updatePassword,
updateProfile,
} from "../controllers/userController.js"
// import {isAuthenticatedUser} from "../Middleware/Auth.js";
import { isAuthenticated } from "../middlewares/auth.js"
import multer from 'multer'
import { isAuthenticatedUser, authorizeRoles } from "../middlewares/auth.js"
const uploaderImage = multer({
storage: multer.diskStorage({}),
fileFilter: (req, file, cb) => {
let ext = path.extname(file.originalname);
if (ext !== ".jpg" && ext !== ".jpeg" && ext !== ".png") {
cb(new Error("File type not supported!"), false)
return
}
cb(null, true);
}
});
const router = express.Router();
router.route("/user/register/").post(uploaderImage.single("image"), registerUser)
router.route("/user/login/").post(loginUser)
router.route("/user/register").post(registerUser);
router.route("/user/login").post(loginUser);
router.route("/user/password/forgot").post(forgotPassword);
router.route("/user/password/reset/:token").put(resetPassword);
router.route("/user/logout").get(logout);
router.route("/user/update/password").put(isAuthenticated, updatePassword);
router.route("/user/details").get(isAuthenticatedUser, getUserDetails);
router.route("/user/password/update").put(isAuthenticatedUser, updatePassword);
router.route("/user/update/profile").put(isAuthenticatedUser, updateProfile);
export default router;

BIN
tmp/tmp-1-1655728922687 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
tmp/tmp-1-1655730583107 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
tmp/tmp-1-1655730644545 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
tmp/tmp-1-1655730940920 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB