Having an error where a logged in user will try to update their account username but run into an error. For the life of me I cannot figure out why it is sometimes (maybe 1/20 users run into this) unable to find the current user. User's can only access this page if logged in. The errors are:
throw er; // Unhandled 'error' event
TypeError: Cannot set property 'username' of null
The error seems to be happening here: user.username = req.body.username;
router.post("/updateAccount", function (req, res) {
if (req.user) {
User.findOne({username: req.body.currentUser}, function (err, user) {
if (err) {
return done(err);
}
user.username = req.body.username;
user.save(function (err) {
if (err) {
req.flash("error", "It looks like that email address is taken.");
res.redirect('back')
} else {
req.logout();
req.login(user, function (err) {
if (err) console.log('There was an account error' + err)
req.flash("success", "Your account has been created! Your username is " + user.username);
res.redirect('/results')
});
}
});
});
} else {
res.redirect('/results')
}
});
user will be null if no matching user can be found by the User.findOne({username: req.body.currentUser} query (as mentioned in the docs).
So you should add another check if that's the case and handle this appropriately:
User.findOne({username: req.body.currentUser}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
// handle this case as user.username = req.body.username will fail
}
// ... rest of the code
Related
This post request creates a new user account and saves a test score data point for a user.
~1/20 users or so run into an error and are redirected back to the previous page thus losing their results.
I have been unable to replicate the error or see any errors in the logs.
Looking for advice on how to change my error handling and or any insight to why this may be occurring.
Thank you!
router.post("/test", function(req, res){
User.findOne({username: req.body.username}, function(err, existingUser) {
console.log('user exists:' + existingUser)
if (err) {
return done(err);
}
if (!existingUser) {
var newUser = new User({username: req.body.username});
User.register(newUser, req.body.password, function(err, user){
user.testscore = req.body.testscore;
user.save()
if(err){
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function(){
res.redirect("/thank-you");
});
});
You can use try-catch along with async-await for error handling. I would write the code like this.
router.post('/test', async (req, res) => {
try {
const user = await User.findOne({username: req.body.username})
if (!user) {
let newUser = new User({username: req.body.username});
// If User.register returns promise then here also you can use await like above.
// If any error occurs catch block will catch it and show the error.
User.register(newUser, req.body.password, function(err, user) {
user.testscore = req.body.testscore;
user.save()
if(err) {
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/thank-you");
});
});
}
} catch (err) {
console.error(err.message)
}
})
Hope it helps to solve your problem.
I've used a soft delete feature in mongodB to disable a user and not delete it permanently. Now, only enabled users can log in to the site while the disabled users can not log in to the site.
// Soft delete feature
exports.getDisabledUsers = function(req,res, next) {
User.find({active: false}, function(err, users) {
if (err) {
res.send(err);
}
res.json(users);
});
}
// Log In
exports.login = function (req, res, next) {
var userInfo = setUserInfo(req.user);
res.status(200).json({
token: 'JWT ' + generateToken(userInfo),
user: userInfo
});
};
// Passport.js
var localLogin = new LocalStrategy(localOptions, function (email, password, done) {
User.findOne({
email: email
}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
error: 'Login failed. Please try again.'
});
}
user.comparePassword(password, function (err, isMatch) {
if (err) {
return done(err);
}
if (!isMatch) {
return done(null, false, {
error: 'Login failed. Please try again.'
});
}
return done(null, user);
});
});
});
Disabled users shouldn't be able to log in. Right now, they are able to log in.
While Disabling the user you can move that data to another collection, that way your disabled user cannot be able to login to your system
exports.disableUser = function (req, res, next) {
User.findByIdAndUpdate({_id:req.params._id}, {active: false}, function (err, users) {
if (err) {
res.send(err);
}
User.findByIdAndRemove(
{_id:req.params._id},
function(err, doc) {
if (doc) {
DisableUser.insertMany(doc, function(err, doc){
// your response
});
} else {
// your response
}
)
});
}
You have not checked user status is active or not. This can be done by adding a condition in code, or modifying mongo query and adding one more condition in findOne.
//CODE
if(!user.active) {
//RETURN USER IS NOT ACTIVE
}
//MONGO QUERY
User.findOne({
email: email,
active: true
}, function (err, user) {
//YOUR CODE
}
Role based login may create some complexity but this can be achieved simply by adding one more collection named disabledUsers
when admin disable any user then the click function do two things at the same time
1)add the email into disabledUser collection
2)delete the user from user collection
Then in your login function just check this way
disabledUser.findOne({email :email },
function (err ,user){
if(err) return done(err)
else{
if(!user){
user.findOne({email : email }
write your login stuff here the wau you r doing
}
else{return alert('user is disabled')}
}
})
I am using express.js with mongoose for signup. I use crypto for saving the user's password and am now working on the login section. However, when I post values via postman, I am getting the error "not exist" over and over again.
Here is my code:
app.post('/login', (req, res) => {
var User = require('./user.js');
User.findOne({ username: req.body.email }, function(err, user) {
if (err) {
console.log("error");
} else if (!user) {
console.log("not exist");
} else if(!user.validPassword(req.body.password)) {
console.log("not valid");
} else {
console.log("valid");
}
});
res.send("XYZ");
});
I'm using NodeJS and passport to let users create an account before they can see results of a quiz they've just taken. My challenge is I need to confirm the username is available before the page refreshes because the user will lose their results if this happens.
Again: I need to verify the username is not taken prior to refreshing.
I think I'm close but it is not working. How would I change my code to handle this challenge?
Currently if the user name is taken it returns an error on trying to create an account and the user ends up on the /failpage as shown below.
app.post('/quiz', usernameToLowerCase, emailToLowerCase, function(req, res) {
User.findOne({
username: req.body.username
}, function(err, user) {
if (err) {
alert(err)
if (user) {
alert('this username is already taken. Please choose another.')
console.log('there was a user');
return false;
}
}
});
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password,
})
user.save(function(err) {
console.log('this is the problem' + ' ' + err)
if (err) {
return res.redirect('/failpage')
}
req.logIn(user, function(err) {
if (err) {
console.log(err);
}
console.log('all looks good')
res.redirect('/results');
});
});
});
Solved it with this if anyone else is trying to do the same thing:
in app.js
app.get('/usercheck', function(req, res) {
User.findOne({username: req.query.username}, function(err, user){
if(err) {
console.log(err);
}
var message;
if(user) {
console.log(user)
message = "user exists";
console.log(message)
} else {
message= "user doesn't exist";
console.log(message)
}
res.json({message: message});
});
});
In js
$('#usercheck').on('change', function() {
$.get('/usercheck?username='+$('#usernameValue').val().toLowerCase(), function(response) {
$('#usernameResponseHidden').text(response.message)
if ($('#usernameResponseHidden').html() === "user exists"){
$('#usernameResponse').text('That username is taken. Please pick another')
}
To solve your problem I think you need to routes. At least a app.get('/quiz') which returns a boolean on if the user exists or not. The section User.findOne can be sent in that route instead. You just need to make a request using ajax when he looses focus of the username field of your form, and display a notification if the name is available or not.
I'm authenticating my nodeJs app using passport local strategy. Everything is working fine. But how can I show the user appropriate message that he has entered invalid login credentials. My present code is just sending 401 unauthorized error on screen.
Here is my code
passport.use(new LocalStrategy(function(username, password, callback) {
User.findOne({
username : username
}, function(err, user) {
if (err) {
return callback(err);
}
// No user found with that username
if (!user) {
return callback(null, false);
}
// Make sure the password is correct
user.verifyPassword(password, function(err, isMatch) {
if (err) {
return callback(err);
}
// Password did not match
if (!isMatch) {
return callback(null, false);
}
// Success
return callback(null, user);
});
});
}));
exports.isLocalAuthenticated = passport.authenticate('local', {
session : true
});
router.post('/', authController.isLocalAuthenticated, function(req, res) {
//here I want to show the error message to user
});
The documentation has clearly described your case under Custom Callback section.
You need to add custom callback like this:
exports.isLocalAuthenticated = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); } //error exception
// user will be set to false, if not authenticated
if (!user) {
res.status(401).json(info); //info contains the error message
} else {
// if user authenticated maintain the session
req.logIn(user, function() {
// do whatever here on successful login
})
}
})(req, res, next);
}
You don't need to specify the latter callback.