How to fix: ReferenceError: validateEmail is not defined - javascript

I'm trying to make Register using EJS. Therefore, I'm checking
If all input fields have values or not
Is Email valid or not
Password Length has to be < 6 characters
Is Email already register or not
And give them a message if they do not comply with the above conditions. To Check all these conditions I have the following code inside the userCtrl.js file
userCtrl.js
const Users = require("../models/userModel");
const userCtrl = {
//! Register User
register: async (req, res) => {
try {
const { name, email, password } = req.body;
// Check If All fields are filled with values or not
if (!name || !email || !password) {
return res.status(400).json({ masg: "Please fill allfields." });
}
// Check If email is valid
if (!validateEmail(email)) {
return res.status(400).json({ masg: "Please enter valid email." });
}
//Check password length
if (password.length < 6) {
return res
.status(400)
.json({ masg: "Password must be atleast 6 characters long." });
}
const user = await Users.findOne({ email });
// Check If email is already registered
if (await Users.findOne({ email })) {
return res.status(400).json({ masg: "User already exists." });
}
res.json({ msg: "User Registered Successfully!" });
} catch (err) {
console.log(err);
return res.status(500).json({ msg: err.message });
}
},
};
//! Exporting User Controller
module.exports = userCtrl;
Here is user Module for refrance.
const mongoose = require("mongoose");
const { Schema } = mongoose;
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Please enter your name"],
trim: true,
},
email: {
type: String,
required: [true, "Please enter your email"],
trim: true,
unique: true,
},
password: {
type: String,
required: [true, "Please enter your password"],
trim: true,
},
role: {
type: Number,
default: 0, // 0 for user, 1 for admin
},
avator: {
type: String,
default:
"https://res.cloudinary.com/manix/image/upload/v1639722719/avator/istockphoto-1214428300-170667a_c4fsdt.jpg",
},
});
//! Exporting User Modules
module.exports = mongoose.model("Users", userSchema);
But when I try to register users using Postman then I got this error.
enter image description here
Please Help me to fix this issue.

The issue is probably happening here
if (!validateEmail(email))
Where is your validateEmail() function located?

Related

Why does bcrypt always return false?

I've been trying to figure out why bcrypt always return false. I've pretty much tried everything and it's pretty much the same results. I've also tried using third party websites to check if the hash and plain password matches but it also returns false. I'm thinking there's an issue with what I HATCHED but I can't seem to figure it out.
Stack: Express, mongoose, mongodb atlas
api calls
login = (req, res, next) => {
let userData = req.body;
User.findOne({
email: userData.email
},function(error,user){
if(error){
console.log(error)
} else {
if(!user){
res.status(401).send('email not found')
} else if(user){
bcrypt.compare(userData.password, user.password).then(function(resp) {
if(resp === false){
res.status(401).send('Invalid password')
} else {
let payload = {
subject: user._id
}
let token = jwt.sign(payload,"secretKey")
res.status(200).send({user,token})
}});
}
}
})
}
register = async (req, res) => {
let userData = req.body;
User.find({
email: userData.email
},function(err,result){
if(err){
console.log(err)
} else if(under._.isEmpty(result)){
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(userData.password, salt, function(err, hash) {
userData.password = hash;
let user = new User(userData)
user.save((error,registerUser)=>{
if(error){
console.log(error)
} else {
let payload = {
subject: registerUser._id
}
let token = jwt.sign(payload,"secretKey")
res.status(200).send({registerUser,token})
}
})
});
})
} else {
res.status(401).send('Email is already in use')
}
})
};
My schema
import mongoose from 'mongoose';
import {
saveUser,
toAuthJSON,
validatePassword,
} from '../helpers/model.helpers';
import { generateAccessToken } from '../helpers/auth.helpers';
const { Schema } = mongoose;
const userSchema = new Schema({
firstName: {
type: String,
required: [true, 'first name is required'],
},
lastName: {
type: String,
required: [true, 'last name is required'],
},
phoneNumber: {
type: String,
required: [true, 'Phone number is required'],
min: [10, 'A phone number can have at-least 10 digits'],
max: [13, 'Please enter a valid phone number, this is too long'],
},
email: {
type: String,
required: [true, 'An Email is required'],
},
password: {
type: String,
required: [true, 'A password is required'],
},
profileImage: {
type: String,
required: false,
},
title: {
type: String,
required: false,
},
companyName: {
type: String,
required: [false, 'Company name is required'],
},
companyAddress: {
type: String,
required: false,
},
companyPhoneNumber: {
type: String,
required: [false, 'Company phone number is required'],
},
companyLogo: {
type: String,
required: false,
},
},{
versionKey: false
});
userSchema.pre('save', saveUser);
userSchema.methods.validatePassword = validatePassword;
userSchema.methods.generateAccessToken = generateAccessToken;
userSchema.methods.toAuthJSON = toAuthJSON;
export default mongoose.model('User', userSchema);
my helper
import bcrypt from 'bcrypt';
export async function saveUser(next) {
const SALT_WORK_FACTOR = 10;
if (!this.isModified('password')) return next();
try {
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
this.password = await bcrypt.hash(this.password, salt);
return next();
} catch (error) {
return next(error);
}
}
export function validatePassword(password) {
return bcrypt.compare(password, this.password);
}
export function toAuthJSON() {
const profile = this.toJSON();
delete profile.password;
// eslint-disable-next-line no-underscore-dangle
delete profile.__v;
return {
profile,
token: this.generateAccessToken(this.id),
};
}

Why I can't able to hash a password using Mongoose Virtual Setter?

I'm trying to 'setter' virtual method to hash my password. However, the password is not hashing. In fact, it is showing undefined every time I try to access the virtual field. If I try to store the data without the hash password then It stores the data. Some days ago, I tried the same code and it worked. But I don't know why It's not working now.
Here is My Code Link: https://github.com/RiyaadHossain/FlipkartClone-Server
Here is the controller code:
// Sign Up Controller_____________________________________
exports.signup = async (req, res) => {
// Check If the email already exists or not
User.findOne({ email: req.body.email }).exec((err, user) => {
if (user) {
res.status(400).json({ message: "Email Already Taken..!" });
}
if (err) {
res.status(500).json({ message: "An Internal Error Occured..!" });
}
});
const { firstName, lastName, email, userName, password } = req.body;
console.log(password); // Getting Undefined - Here is the problem
// Create New User
const newUser = new User({ firstName, lastName, email, userName, password }); // Error is with the password
newUser.save((err, data) => {
if (err) {
console.log(err);
res.status(500).json({ error: err.message });
}
if (data) {
res.status(500).json({ data });
}
});
};
Here is the virtual setter code:
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20,
},
lastName: {
type: String,
required: true,
trim: true,
min: 3,
max: 20,
},
userName: {
type: String,
required: true,
unique: [true, "User Name already Taken"],
index: true,
trim: true,
min: 3,
max: 20,
},
email: {
type: String,
unique: true,
},
hash_password: {
type: String,
required: true,
},
role: {
type: String,
enum: ["user", "admin"],
default: "user",
},
contactInfo: String,
},
{
timestamps: true,
}
);
// Hash Password using Bcrypt
userSchema.virtual("password").set(function (password) {
this.hash_password = bcrypt.hashSync(password, 10);
});
// Instance Method - To compare password
userSchema.methods = {
authenticate: function (password) {
return bcrypt.compareSync(password, this.hash_password);
},
};
module.exports = new mongoose.model("User", userSchema);
Previous code Link Where I was able to do that:
Controller Code: https://github.com/RiyaadHossain/FlipkartClone-Practice-Server/blob/main/src/controller/auth.js
Model Code: https://github.com/RiyaadHossain/FlipkartClone-Practice-Server/blob/main/src/models/user.js
try change const newUser = new User({ firstName, lastName, email, userName, password }) to
const newUser = new User()
newUser.firstName = firstName
newUser.lastName = lastName
newUser.email = email
newUser.userName = userName
newUser.password = password

MongoDB document naming

I have tried so many time different things but unable understand that whenever I am saving data into MongoDB why am I getting the name of that document as below
User.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: {
type: String,
require: true,
unique: true,
lowercase: true,
},
username: {
type: String,
require: true,
unique: true,
maxLength: 7,
},
password: {
type: String,
require: true,
minLength: 8,
},
});
const User = mongoose.model("user", userSchema);
module.exports = User;
When I have saved the data by hitting API through postman and printing the data in console, the data I am receiving is as below:
email {
_id: new ObjectId("627a4ae94b8958e3fe968311"),
email: 'abc#abc.com',
username: 'fzee07',
password: 'test1234',
__v: 0
}
So my question is this that why this object is getting saved and named as "email".
registerUser.js
const User = require("../../models/User");
const registerUser = async (req, res) => {
const { email, username, password } = req.body;
try {
const e_mail = await User.findOne({});
console.log("email", e_mail);
if (e_mail.email === email) {
res.status(409).json({
success: false,
msg: "User already exists",
});
} else {
if (username.length < 8) {
if (password.length >= 8) {
const user = User.create({ email, username, password });
res.status(201).json({
success: true,
data: "User Created",
});
} else {
res.status(401).json({
success: false,
data: "Password muste be minimum 8 characters",
});
}
} else {
res.status(401).json({
success: false,
data: "Username must be less than 8 characters",
});
}
}
} catch (err) {
console.log(err);
}
};
module.exports = registerUser;
I understand the problem now. Sorry about the confusion, I misread the second part of your question. The reason you're getting this in console:
email {
_id: new ObjectId("627a4ae94b8958e3fe968311"),
email: 'abc#abc.com',
username: 'fzee07',
password: 'test1234',
__v: 0
}
Is because you are console logging the string "email", then your user object from the database, which you have confusingly named e_mail.
Change the log message to look like this, and you're good:
console.log("user", e_mail);
In fact, your code needs some severe refactoring. Right now, it's not very readable. Here's an improvement:
const User = require('../../models/User');
const registerUser = async (req, res) => {
const { email, username, password } = req.body;
try {
// Find a user with that email
const user = await User.findOne({ email });
console.log('user', user);
// if it exists, return
if (user) {
res.status(409).json({
success: false,
message: 'User already exists',
});
return;
}
// Validate the username and password
// If validates, create the user
if (username.length < 8 && password.length >= 8) {
const newUser = User.create({ email, username, password });
res.status(201).json({
success: true,
message: 'User created',
data: newUser,
});
return;
}
// If all else fails, return 401
res.status(401).json({
success: false,
message: 'Username must be less than 8 characters & password must be at least 8 characters long',
});
} catch (err) {
res.status(500).json({
success: false,
message: 'Server error',
});
}
};
module.exports = registerUser;
I changed all the places where you had the key of data to have the key of message, as messages were the values.
Once again though, I really recommend doing the validation in Mongoose middleware/hooks instead of right within the route. Will save you headaches as your application grows.

Problem with Schema recognition in node.js

I'm trying to make a login page and send the info to a Mongodb database. But I'm running into a reference error and have no idea why.
My Mongoose Schema is as follows:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var validateEmail = function(email) {
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
return re.test(email)
};
var userSchema = new Schema({
full_name: { type: String, required: [true, 'Full name must be provided'] },
email: {
type: String,
Required: 'Email address cannot be left blank.',
validate: [validateEmail, 'Please fill a valid email address'],
match: [/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'Please fill a valid email address'],
index: {unique: true, dropDups: true}
},
password: { type: String , required: [true, 'Password cannot be left blank']},
dob: { type: Date , required: [true, 'Date of birth must be provided']},
country: { type: String , required: [true, 'Country cannot be left blank.']},
gender: { type: String , required: [true, 'Gender must be provided']},
});
module.exports = mongoose.model('Users', userSchema);
When i try running the following code i get the message:
**var User = mongoose.model('Users', userSchema);
ReferenceError: userSchema is not defined**
var mongoose = require('mongoose');
var crypto = require('crypto'), hmac, signature;
const { check, validationResult } = require('express-validator/check');
const { matchedData, sanitize } = require('express-validator/filter');
var User = mongoose.model('Users', userSchema);
/* POST user registration page. */
router.post('/register',[
check('full_name','Name cannot be left blank')
.isLength({ min: 1 }),
check('email')
.isEmail().withMessage('Please enter a valid email address')
.trim()
.normalizeEmail()
.custom(value => {
return findUserByEmail(value).then(User => {
//if user email already exists throw an error
})
}),
check('password')
.isLength({ min: 5 }).withMessage('Password must be at least 5 chars long')
.matches(/\d/).withMessage('Password must contain one number')
.custom((value,{req, loc, path}) => {
if (value !== req.body.cpassword) {
// throw error if passwords do not match
throw new Error("Passwords don't match");
} else {
return value;
}
}),
check('gender','Please select gender')
.isLength({ min: 1 }),
check('dob','Date of birth cannot be left blank')
.isLength({ min: 1 }),
check('country','Country cannot be left blank')
.isLength({ min: 1 }),
check('terms','Please accept our terms and conditions').equals('yes'),
], function(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.json({status : "error", message : errors.array()});
} else {
hmac = crypto.createHmac("sha1", 'auth secret');
var encpassword = '';
if(req.body.password){
hmac.update(req.body.password);
encpassword = hmac.digest("hex");
}
var document = {
full_name: req.body.full_name,
email: req.body.email,
password: encpassword,
dob: req.body.dob,
country: req.body.country,
gender: req.body.gender,
calorie: req.body.calorie,
salt: req.body.salt
};
var user = new User(document);
user.save(function(error){
console.log(user);
if(error){
throw error;
}
res.json({message : "Data saved successfully.", status : "success"});
});
}
});
function findUserByEmail(email){
if(email){
return new Promise((resolve, reject) => {
User.findOne({ email: email })
.exec((err, doc) => {
if (err) return reject(err)
if (doc) return reject(new Error('This email already exists. Please enter another email.'))
else return resolve(email)
})
})
}
}
module.exports = router;```
Any ideas why the schema can't be found. (Im new to node.js and webframeworks)

Why do I get a 400 error when logging a user using bcrypt?

I'm trying to create login authentication, but I keep getting an 400 error in Postman saying that my syntax is bad when testing things out. I'm pretty sure my entire User model is solid, but for good measure, I've attached the whole thing in case something's off there. Otherwise, I'm really not sure what the problem is or where to go from here.
This is the data that I'm sending that triggers the 400 Bad Request (the request cannot be fulfilled due to bad syntax) and logs the invalid password to the console:
{
"email": "andrew#example.com",
"password": "Red12345!"
}
Here's my entire user model code:
const mongoose = require('mongoose')
const validator = require('validator')
const bcrypt = require('bcryptjs')
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
unique: true,
require: true,
trim: true,
lowercase: true,
validate(value) {
if(!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
age: {
type: Number,
default: 0,
validate(value) {
if(value < 0) {
throw new Error('Age must be a positive number.')
}
}
},
password: {
type: String,
trim: true,
lowercase: true,
required: true,
minlength: 7,
validate(value) {
if(value.toLowerCase().includes("password")) {
throw new Error("Password can't be 'password'.")
}
}
}
})
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email })
if (!user) {
throw new Error('User not found')
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch) {
throw new Error('Invalid password')
}
return user
}
//Hash the plain text password before saving
userSchema.pre('save', async function (next) {
const user = this
if(user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next()
})
const User = mongoose.model('User', userSchema)
module.exports = User
And here's the user login router:
router.post('/users/login', async (req, res) => {
try {
const user = await User.findByCredentials(req.body.email, req.body.password)
res.send(user)
} catch (e) {
console.log(e.message)
res.status(400).send()
}
})

Categories

Resources