I am trying to create a route to register users for my application, but I ran into a problem. When hitting the /register route, I get the following error:
TypeError: user.setPassword is not a function at
Here is my code:
models/Users.js
var mongoose = require('mongoose');
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var UserSchema = new mongoose.Schema({
username: {type: String, lowercase: true, unique: true},
hash: String,
salt: String
});
UserSchema.methods.setPassword = function(password){
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
};
UserSchema.methods.validPassword = function(password) {
var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
return this.hash === hash;
};
UserSchema.methods.generateJWT = function() {
// set expiration to 60 days
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
_id: this._id,
username: this.username,
exp: parseInt(exp.getTime() / 1000),
}, 'SECRET');
};
mongoose.model('User', UserSchema);
routes/index.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');
router.post('/register', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
var user = new User();
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function (err){
if(err){ return next(err); }
return res.json({token: user.generateJWT()})
});
});
module.exports = router;
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//MongoDB Setup
var mongoose = require('mongoose');
require('./models/Users');
mongoose.connect('mongodb://localhost/images');
var passport = require('passport');
require('./config/passport');
var routes = require('./routes/index');
var app = express();
app.use(passport.initialize());
.
.
.
module.exports = app;
I'm fairly new to the MEAN stack, and after scouring the code for a few hours I can't see why things are going wrong.
Below is my code and it works for me.
-----User Model
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const userSchema = new mongoose.Schema({
name:{
type: String,
required: [true, 'Pleae enter your name']
},
email:{
type: String,
required: [true, 'Please enter your email address'],
unique: true,
validate: [validator.isEmail, 'Please enter a valid email address']
},
role: {
type: String,
enum:{
values: ['user', 'employer'],
message : 'Please select your role'
},
//required: [true, 'Please select role that is required'],
default: 'user'
},
password :{
type: String,
required: [true, 'Please enter password for your account'],
minlength: [8, 'Your password must be a t leeast 8 characters long'],
select: false
},
createdAt: {
type: Date,
default: Date.now
},
resetPasswordToken: String,
resetPasswordExpire: Date
});
//Encryting Passwords before Saving
userSchema.pre('save', async function(next){
this.password = await bcrypt.hash(this.password, 10);
});
//Return JSON web token
userSchema.methods.getJwtToken = function(){
return jwt.sign({id: this._id}, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_TIME
});
}
//Compare password in database
userSchema.methods.comparePassword = async function(enterPassword){
return await bcrypt.compare(enterPassword, this.password);
}
module.exports = mongoose.model('User', userSchema);
-----Auth Controller
const User = require('../models/users');
const catchAsyncErrors = require('../middlewares/catchAsyncErrors');
const ErrorHandler = require('../utils/errorHandler');
//Register a new user ==> /api/v1/user/register
exports.registerUser = catchAsyncErrors(async(req, res, next) => {
const { name, email, password, role} = req.body;
const user = await User.create({
name,
email,
password,
role
});
//Create JWT Token
const token = user.getJwtToken();
res.status(200).json({
succes: true,
message: 'User created succesfully',
data: user,
token: token
})
});
//Loguin user => /api/v1/login
exports.loginUser = catchAsyncErrors( async(req, res, next) =>{
const { email, password } = req.body;
if(!email || !password){
return next (new ErrorHandler('Please enter email and password'), 400);
}
//Finding user in database
const user = await (await User.findOne({email})).isSelected('+password');
if(!user){
return next(new ErrorHandler('Invalid Email or Password', 401));
}
//Check if passwoerd is correct
const isPasswordMatched = await user.comparePassword(password);
if(!isPasswordMatched){
return next (new ErrorHandler('Invalid Email or Password', 401));
}
//Create JSOBN Web Token
const token = user.getJwtToken();
res.status(200).json({
succes: true,
token
})
})
Try to do this:
models/Users.js
var mongoose = require('mongoose');
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var UserSchema = new mongoose.Schema({
username: {type: String, lowercase: true, unique: true},
hash: String,
salt: String
});
UserSchema.methods.setPassword = function(password){
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
};
UserSchema.methods.validPassword = function(password) {
var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
return this.hash === hash;
};
UserSchema.methods.generateJWT = function() {
// set expiration to 60 days
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
_id: this._id,
username: this.username,
exp: parseInt(exp.getTime() / 1000),
}, 'SECRET');
};
// exports the user schema
module.exports = mongoose.model('User', UserSchema);
routes/index.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var mongoose = require('mongoose');
var User = require('models/user'); // require the user model in the correct path
// line removed
//var User = mongoose.model('User');
router.post('/register', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
var user = new User();
user.username = req.body.username;
user.setPassword(req.body.password);
user.save(function (err){
if(err){ return next(err); }
return res.json({token: user.generateJWT()})
});
});
module.exports = router;
Let me know if this works.
Funny: Always make sure your files are not saved in some funky location. I had a copy of Users.js in my stylesheets/ folder and that was the copy I was working on this entire time. The copy in models/ in the meantime was full of little buggy things that were easy to spot.
Related
I have creating one ecommerce application, Inside this i have facing some issue regarding req.gravatar() is not a function.
Whenever I have send data through postman give me error, those error I have defined above.
account.js file code
const router = require('express').Router();
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const config = require('../config');
var gravatar = require('gravatar');
router.post('/signup', (req, res, next) => {
let user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.password = req.body.password;
user.picture = req.gravatar();
user.isSeller = req.body.isSeller;
User.findOne({ email: req.body.email }, (err, existingUser) => {
if(existingUser) {
res.json({
success: false,
message: 'Account with that email is already exist'
});
}
else{
user.save();
var token = jwt.sign({
user: user
}, config.secret, {
expiresIn: '7d'
});
res.json({
success: true,
message: 'Enjoy your token',
token: token
});
}
});
});
module.exports = router;
User.js file code
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const crypto = require('crypto');
const UserSchema = new Schema({
email: { type: String, unique: true, lowercase: true },
name: String,
password: String,
picture: String,
isSeller: { type: Boolean, default: false },
address: {
add1: String,
add2: String,
city: String,
state: String,
country: String,
postalCode: String
},
created: { type: Date, default: Date.now }
});
UserSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.hash(user.password, null, null, function(err, hash) {
if(err) return next(err);
user.password = hash;
next();
});
});
UserSchema.methods.comparePassword = function(password) {
return bcrypt.compareSync(password, this.password);
}
UserSchema.methods.gravatar = function(size) {
if(!this.size) size = 200;
if(!this.email) {
return 'https://gravatar.com/avatar/?s' + size + '&d=retro';
}
else{
var md5 = crypto.createHash('md5').update(this.email).digest('hex');
return 'https://gravatar.com/avatar/' + md5 + '?s' + size + '&d=retro';
}
}
module.exports = mongoose.model('User', UserSchema);
please help me to solve this question as fast as possible.
because i am Amateur developer in node.js technology.
In the following line, gravatar is not an attribute of req and therefore cannot be invoked as a function
user.picture = req.gravatar();
I suppose that what you want to do, is something like:
user.picture = gravatar.url(user.email);
With this change, user.picture will contain the URL of the gravatar user profile picture for that email.
I did the registration portion successfully now I am trying to delete the registered user by id . This is how I did
user controller
const mongoose = require ('mongoose');
const User = mongoose.model('User');
module.exports.register = (req, res, next) =>{
var user = new User();
user.fullName = req.body.fullName;
user.email = req.body.email;
user.password = req.body.password;
user.phoneNumber = req.body.phoneNumber;
user.save((err, doc) =>{
if(!err)
res.send(doc);
else{
if (err.code == 11000)
res.status(422).send(["Entered duplicate email address. Please check"]);
else
return next(err);
}
});
}
And in my index router
const express = require ('express');
const router = express.Router();
const ctrlUser = require ('../controllers/user.controller.js');
// routing functions
router.post('/register' , ctrlUser.register);
router.delete('/:userId' , (req, res, next) =>{
User.remove({_id: req.params.userId})
.exec()
.then(result => {
res.status(200).send(["Deleted"]);
})
.catch(err =>{
if (err.code == 500)
res.status(500).send(["Didn't get deleted"]);
else
return next(err);
});
});
module.exports = router;
When I am testing in postman I am not getting any response. Where did I make the mistake ? Something am I missing out ?
EDIT:- Including user.model
const mongoose = require ('mongoose');
const bcrypt = require('bcryptjs');
//define user schema
var userSchema = new mongoose.Schema({
fullName : {
type: String,
required: "Full name can't be empty"
},
email : {
type: String,
required: "Email can't be empty",
unique: true
},
password : {
type: String,
required: "Password can't be empty",
minlength: [6 ,"Password must be atleast 6 character long"]
},
phoneNumber : {
type: String,
required: "Reqired for further contact.Can't be empty"
},
saltSecret: String //this is user for encryption and decryption of password
});
mongoose.model('User', userSchema);
I have a problem with mongoose. I try to set two properties using Schema methods but they won't save at all.
User Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const crypto = require("crypto");
const UserSchema = new Schema({
email: {
type: String,
unique: true,
required: true
},
password: {
type: String
},
salt: String
});
UserSchema.methods.passwordHash = password => {
this.salt = crypto.randomBytes(16).toString("hex");
this.password = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, "sha512")
.toString("hex");
};
...
module.exports = User = mongoose.model("user", UserSchema);
I took the passwordHash method from this tutorial
Index.js
const User = require("../../models/User");
...
const newUser = new User();
newUser.email = email;
newUser.passwordHash(password);
newUser.save(err => {
if (err) return res.send({ message: "Server error" });
});
All I get is:
I found the problem - I used the arrow function so this refers to the original context not the current model:
UserSchema.methods.passwordHash = function(password) {
this.salt = crypto.randomBytes(16).toString("hex");
this.password = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, "sha512")
.toString("hex");
};
I am working on a test signup with nodejs, i set up a free mongo lab database and testing signups on my local server. i keep getting this error an on my route, i can console upto var user = new User(); (console- user) and get the objects . I can console user.profile and console will display name and picture as objects etc. but for some reason my code is saying user.profile.name is undefined . Any error you guys can spot ?
this is my model
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var Schema = mongoose.Schema;
var UsersSchema = new Schema({
email: {
type: String,
unique: true,
lowercase: true
},
password: String,
profile: {
name: { type: String, default: '' },
picture: { type: String, default: '' }
},
address: String,
history: [{
date: Date,
paid: { type: Number, default: 0 },
}]
});
UsersSchema.pre('save',function(next){
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(10, function(err, salt){
if(err) return next(err);
bcrypt.hash(user.password,salt, null,function(err,hash){
if (err) return next(err);
user.password = hash;
next();
});
})
})
UsersSchema.methods.comparePassword = function(password){
return bcrypt.compareSync(password, this.password)
}
module.exports = mongoose.model('User',UsersSchema);
this my route file
var router = require('express').Router();
var User = require('../models/users');
// var user = new User();
// console.log('user',user.profile.name);
router.post('/signup', function(req, res, next) {
var user = new User();
user.profile.name = req.body.name;
user.email = req.body.email;
user.password = req.body.password;
User.findOne({ email: req.body.email }, function(err, existingUser) {
if (existingUser) {
return res.redirect('/signup');
} else {
user.save(function(err, user) {
if (err) return next(err);
res.json("New user has been created");
});
}
});
});
module.exports = router;
//res.json("New user has been created")
You'll have to assign profile to something first as user is defined but user.profile is not
defined user.profile = '' before the line user.profile.name = req.body.name
or replace the following and try
-var User = require('../models/users'); with var UsersSchema = require('../models/users');
-var user = new User(); with var user = new UsersSchema();
You are trying to access name property from profile, which is not defined.
var user = new User();
user.profile.name = req.body.name;
-----------/\
To make this work, first define profile:
var user = new User();
user.profile = {};
user.profile.name = req.body.name;
I am using node and mongoose to build an app. And when testing, there exists a strange problem. Here is my auth.index.js(for user login).
auth.index.js:
var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var config = require('../config/environment');
var User = require('../api/user/user.model');
var jwt = require('jsonwebtoken');
var auth = require('./auth.service');
var router = express.Router();
router.post('/login', function (req, res, next){
User.find({email: req.body.email}, function (err, user){
if (err) {
return next(err);
} else if (!user) {
return res.json({message: 'Invalid email.'});
} else {
if(!user.authenticate(req.body.password)){
return res.json({message: 'Invalid password.'});
};
var token = auth.signToken(user._id, user.username, user.role);
return res.json({token: token});
};
});
});
Here is the user.model.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String,
password: String,
email: {type: String, lowercase: true},
role: {type: String, default: 'user'},
provider: String,
date: String
});
UserSchema.methods = {
//check password
authenticate: function(plainText) {
return plainText === this.password;
}
};
However, in the command window, it returns that
user.authenticat is not a function.
I wanna know why, and does it mean that I cannot use the method directly or I need to invoke the method through passport ? Thanks.
I think you have misplaced your methods. It should be like this.
UserSchema.methods.authenticate: function(plainText) {
return plainText === this.password;
}
See the following link for the complete example. https://scotch.io/tutorials/using-mongoosejs-in-node-js-and-mongodb-applications