I'm bulding a node.js backend for a webapp and when i submit a form, i do various validations. One of them is to check if an invitation already exists with the same email address.(isUserAlreadyInvited function)
I created a function for this, however when i call this, i guess the response is not that fast and it just moves to the next statement even if the check returns true. How
//Loop through emails one by one
var emails_to_invite = ["test#test.com","invalid.com"];
var response_items = [];
async.each(emails_to_invite,
function(email, callback){
//Response item
var response_item = {}
response_item.email = email;
//Validate
if(Joi.validate({ email: email }, apiSchema).error) {
response_item.error = "not valid email";
response_items.push(response_item);
callback();
} else if(email == user.email) {
response_item.error = "Sending an invitation to your own email is kinda dumb";
response_items.push(response_item);
callback();
} else if(isUserAlreadyInvited(email,user_id)) {
response_item.error = "already invited";
response_items.push(response_item);
callback();
} else {
sendInvitationEmail(email,user_id,null,null,function(invitation_code){
if(invitation_code) {
response_item.invitationCode = invitation_code;
} else {
response_item.error = "server error";
}
response_items.push(response_item);
callback();
});
};
},
function(err){
//Return response
res.status(200).send(response_items);
}
);
function isUserAlreadyInvited(email,invited_by) {
User.findOne({
email: email,
invited_by: invited_by
}, function(err, user) {
if(err) {
return false;
} else {
return true;
}
});
}
Two returns here:
function isUserAlreadyInvited(email,invited_by) {
User.findOne({
email: email,
invited_by: invited_by
}, function(err, user) {
if(err) {
return false;
} else {
return true;
}
});
}
are defined inside this function
function(err, user) {
if(err) {
return false;
} else {
return true;
}
}
and have nothing with return value of isUserAlreadyInvited().
Apparently your isUserAlreadyInvited() is an asynchronous function that needs to be treated asynchronously - it shall get callback function as a parameter. That callback shall be invoked in place of that function(err, user) {}
Related
I am trying to add a custom validation rule to check if username exists or not. My code:
jQuery.validator.addMethod("checkexist", function(myvalue, element) {
checkifexist(function(result) {
if (result == true)
{
return true;
}
else
{
return false;
}
});
}, 'Does not exists!');
and
async function checkifexist(callback) {
const secret = keytar.getPassword('Userdata', 'MysqlPassword');
secret.then((result) => {
var mysql = require("mysql");
var connection = mysql.createConnection({
host: store.get('ip'),
port: store.get('port'),
user: store.get('username'),
password: result,
database: "database"
});
var querystring = 'SELECT * FROM `testdb`';
try
{
connection.query(querystring, (err, rows, fields) => {
if(err){
return callback("error with query", err);
}
var found;
for (var i in rows)
{
if (some check...)
{
return callback(true);
}
}
return callback(false);
});
connection.end(() => {
});
}
catch { }
});
However, if I check the valditation it correctly outputs true or false on every keypress. I still get only validation errors, though it should be a valid input.
I am trying to validate the user before accessing the content. I have declared function globally and passing it inside the body. When I run it , I am getting error has: user doesn't exist . Please let me know where I am going wrong.
function validate(user_id){
var user_id = db.query('select user_id from user WHERE user_id = ?', [user_id],
function(error,rows) {
if (user_id != user_id) {
return false;
} else {
return true;
}
});
}
router.post('/addcustomerskills', function(req,res) {
if (validate(user_id == true)) {
return true;
// my code should execute
}else {
response.success= false;
response.mssg = "User Doesn't Exist";
res.json(response);
}
function validate(user_id, req, res){
db.query('select user_id from user WHERE user_id = ?', [user_id], function(error,rows) {
if (error || rows.length === 0) {
var response = {}
response.success= false;
response.mssg = "User Doesn't Exist";
res.json(response);
} else {
// my code should execute
return true;
}
});
}
router.post('/addcustomerskills', function(req,res) {
validate(req.body.user_id, req, res);
})
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I'm using the 'user-management' package in Node, and I have a callback within a callback, within a callback. But the final result doesn't return. This is my main NodeJS module:
playerManagement.login(data.username, data.pw, function (result) {
console.log(result) <-- statement never reached
if (result == "fail") {
socket.emit('client', { type: 'login', result : 'fail'});
} else {
connections[playerindex++] = {'username' : username, 'sockid' : socket.id, 'token' : result };
socket.emit('client', { type: 'login', result : 'success', username : username });
console.log(connections);
}
});
Then I have an external module with the function:
playerModule.prototype.login = function(username, password) {
var o = this;
o.user.load(function (err) {
if (!err) {
o.user.authenticateUser(username, password, function(err, result) {
if (!result.userExists) {
console.log('Invalid username');
return "fail";
} else if (!result.passwordsMatch) {
console.log('Invalid password');
return "fail";
} else {
console.log('User token is: ' + result.token); <--- this is reached.
return result.token;
}
});
} else {
console.log('error logging in');
return "fail";
}
});
So I'm guessing I need to return the value to the "load" function callback, but I'm not sure how to do that.
Change the definition of login with the following.
playerModule.prototype.login = function(username, password, callback) {
var o = this;
o.user.load(function (err) {
if (!err) {
o.user.authenticateUser(username, password, function(err, result) {
if (!result.userExists) {
console.log('Invalid username');
return callback("fail");
} else if (!result.passwordsMatch) {
console.log('Invalid password');
return callback("fail");
} else {
console.log('User token is: ' + result.token); <--- this is reached.
return callback(result.token);
}
});
} else {
console.log('error logging in');
return callback("fail");
}
});
So I'm trying to create a sign up route that checks to see if the user exists first and i have the database call in a separate function that needs to return true or false when it's done. The problem is i'm not very familiar with callbacks and the whole asynchronous thing everything that i have searched for does not seem to work keeps giving me.
TypeError: callback is not a function
This is my code any help or direction would be appreciated.
function pullUserFromDatabase(username, callback) {
console.log(username); //for debug
mongodb.connect(url, function(err, db) {
if(err) {
console.log("didn't get far" + err) //for debug
}
var collection = db.collection(username);
collection.findOne({username}, function(err, item) {
if(err) {
console.log("nope it broke" + err) //for debug
} else {
console.log("it worked" + JSON.stringify(item)) //for debug
callback(true);
}
});
});
}
app.post("/signup", function(req, res) {
var username = req.headers["username"],
password = req.headers["password"],
randomSalt = crypto.randomBytes(32).toString("hex"),
passwordHashOutput = crypto.createHash('sha256').update(password + randomSalt).digest("hex");
if(!username || !password) {
res.send("Username or password not provided.")
} else if(pullUserFromDatabase(username)) {
res.send("User exist.")
}
});
You need to use the callback as follows:
function pullUserFromDatabase(data, callback) {
console.log(data.username); //for debug
mongodb.connect(url, function(err, db) {
if(err) {
console.log("didn't get far" + err) //for debug
}
var collection = db.collection(data.collection);
collection.find({"username": data.username}).count(function (err, count) {
callback(err, !! count);
});
});
};
app.post("/signup", function(req, res) {
var username = req.headers["username"],
password = req.headers["password"],
randomSalt = crypto.randomBytes(32).toString("hex"),
passwordHashOutput = crypto.createHash('sha256').update(password + randomSalt).digest("hex");
if(!username || !password) {
res.send("Username or password not provided.")
}
var data = {
username: username,
collection: "collectionName"
}
if(!username || !password) {
res.send("Username or password not provided.")
}
pullUserFromDatabase(data, function(err, exists) {
if (err) {
res.send(400, "Error - " + err);
}
else if(exists) {
res.send(200, "User exists.");
}
res.send(200, "User does not exist.");
});
});
The reason that callback is undefined is because you didn't pass a 2nd argument to pullUserFromDatabase(username) Provide a 2nd argument, eg. pullUserFromDatabase(username, function(result) {/* do something here with the result variable */})
If you're not very familiar with aync & callbacks, you might find it more intuitive to use promises, but that comes with its own learning curve.
In the context of the original code, this looks like:
...
if(!username || !password) {
res.send("Username or password not provided.");
return;
}
pullUserFromDatabase(username, function(result) {
if(result) {
res.send("User exist.");
} else {
// TODO: Handle this case. If res.send() is never called, the HTTP request won't complete
}
});
...
Also, you need to ensure your callback is always invoked. Add callback(false):
console.log("nope it broke" + err); //for debug
callback(false);
Do a similar step after "didn't get far" and then return so the callback doesn't get invoked multiple times.
I'm new to NodeJS, and have written a method to create a new user, but I need to validate the parameters passed. I'm attempting make sure that an email is not registered twice. This doesn't work, because it checks if the error array is empty before the self.emailExists() callback is completed, how do I fix this?
userSchema.statics.buildUser = function(email, name, cb) {
var self = this;
var user = new this();
var errors = [];
if (!validator.isEmail(email)) {
errors.push({
'err': -1,
'msg': 'Invalid email'
});
} else {
self.emailExists(email, function(exists) {
if (exists) {
errors.push({
'err': -1,
'msg': 'Email address is already in use'
});
} else {
user.email = email;
}
});
}
if (!validator.trim(name).length > 0) {
errors.push({
'err': -1,
'msg': 'Invalid name'
});
} else {
user.name = name;
}
if (errors.length != 0) {
cb(errors, null);
} else {
cb(false, user);
}
}
My emailExists method is:
userSchema.statics.emailExists = function(email, cb) {
var self = this;
self.count({email: email}, function (err, count) {
cb(count > 0);
});
}
You need to restructure your code to put the errors.length check in emailExists() callback. Try Async.js and Promises to manage asynchronous calls better