findOneAndUpdate promise always resolving. Why? - javascript

I made email verification function and problem is that findOneAndUpdate function always resolve no matter what.
I have empty database, so I guess findOneAndUpdate function should fail, but it succeeds.
I guess my mistake is somewhere in this function
User.activate = function(activationLink) {
return new Promise(function(resolve, reject) {
usersCollection.findOneAndUpdate({"activationLink": activationLink}, {"$set": {"isActivated": true}}).then(function(userDoc) {
if (userDoc) {
resolve('Your account has been activated!')
} else {
reject('This account does not exist!')
}
}).catch((e) => {
reject(e)
})
})
}
I'll add this just in case.
userController.js:
exports.activate = function(req, res){
User.activate(req.params.activationLink).then((result) => {
res.send(result)
}).catch((e) => {
res.send(e)
})
}
router.js:
router.get('/activate/:activationLink', userController.activate)

Related

Returning empty result from equalTo in Firebase Cloud Function

I need to handle the case when my database does not have any matching results for equalTo(). Currently the code below only returns if I have a matching item, in the case that there is no match it does not return at all. Please advise on how to handle this?
function getActivitySurvey(pin) {
return new Promise((resolve, reject) => {
var ref = admin.database().ref("activity-survey");
ref.orderByChild("pin").equalTo(pin.toString()).once('child_added')
.then((snapshot) => {
if (snapshot) {
resolve(snapshot);
} else {
reject(new Error('No ActivitySurvey'));
}
}).catch( () => {
reject(new Error('No snapshot'));
})
})
}
Edit:
I've since modified the code to look like the below, in the event that a pin value that does not exist in the database is specified the only line that gets output to the console is 'getActivitySurvey', the function eventually times out but never returns:
function getActivitySurvey(pin) {
return new Promise((resolve, reject) => {
console.log('getActivitySurvey')
var ref = admin.database().ref("activity-survey");
ref.orderByChild("pin").equalTo(pin.toString()).once('child_added').then((snapshot) => {
console.log('have snapshot')
if (snapshot.exists()) {
resolve(snapshot);
} else {
console.log('Rejecting ActivitySurvey')
reject('error');
}
}).catch( (err) => {
console.log('Caught error')
reject('err');
})
})
}
You cannot detect whether a child exists with just a child_added listener. You'll need to use a value listener for that.
For example:
ref.orderByChild("pin").equalTo(pin.toString())
.once('child_added')
.then((snapshot) => {
resolve(snapshot);
});
ref.orderByChild("pin").equalTo(pin.toString()).limitToFirst(1)
.once('value')
.then((snapshot) => {
if (!snapshot.exists()) {
reject(new Error('No ActivitySurvey'));
}
});
Or with only one query:
ref.orderByChild("pin").equalTo(pin.toString()).limitToFirst(1)
.once('value')
.then((snapshot) => {
if (snapshot.exists()) {
snapshot.forEach(function(child) { // will loop only once, since we use limitToFirst(1)
resolve(child);
});
}
else {
reject(new Error('No ActivitySurvey'));
}
});

Express: Resolved Promise going to catch Call

I am trying to send the data from a promise, using Promise chaining the Promise is getting resolved. But the catch call is running not then call
Here is the code from where I am returning the data using Promise:
UserSchema.statics.findByCredentials = function(email, password) {
const User = this;
return User.findOne({
email
}).then((user) => {
if(!user) {
return Promise.reject();
}
try {
return new Promise((reject, resolve) => {
bcrypt.compare(password, user.password, (err, res) => {
// console.log(res);
if(res)
resolve(user);
else
reject("Invalid Credentials");
});
});
}
catch(error) {
Promise.reject(error);
}
});
};
Here is the Promise chain call, where catch call is working not the then call
app.post('/users/login', (req, res) => {
const body = _.pick(req.body, ['email', 'password']);
// console.log(body);
User.findByCredentials(body.email, body.password)
.then((user) => {
}).catch(error => {
error.generateAuthToken().then((token) => {
res.header('x-auth',token).send(error);
});
});
});
Hi tweaked the code, to have another call on the catch.
Could be there any better solution for that.
It's sure that the data is being returned that means, Promise is resolved.

Error: TypeError: Cannot read property 'catch' of undefined when trying to register user for website node.js

I seem to have messed up one of my promises (I think) in a javascript function that is supposed to register a user. I have included the post request and the actual function itself.
app.post("/register", (req, res) => {
dataServiceAuth.registerUser(req.body).then(() => {
res.render("register", {successMessage: "User created"});
}).catch((err) => {
res.render("register", {errorMessage: err, user: req.body.user});
});
});
module.exports.registerUser = function (userData) {
return new Promise(function (resolve, reject) {
if (userData.password != userData.password2) {
reject("Passwords do not match");
}
else {
let newUser = new User(userData);
newUser.save((err) => {
resolve();
}).catch((err) => {
if (err) {
if (err.code == 11000) {
reject('User Name already taken');
}
else {
reject('There was an error creating the user: ${err}');
}
}
});
}
});
};
If newUser.save can return a promise, you definitely shouldn’t be passing a callback to it, or even using the Promise constructor at all. If you really want to reject with strings, the way to implement that would be by transforming rejections from newUser.save() with .catch into new rejections by returning them, and returning the resulting promise from registerUser:
module.exports.registerUser = function (userData) {
if (userData.password != userData.password2) {
return Promise.reject("Passwords do not match");
}
let newUser = new User(userData);
return newUser.save().catch((err) => {
if (err.code == 11000) {
return Promise.reject('User Name already taken');
}
else {
return Promise.reject('There was an error creating the user: ${err}');
}
});
};

JavaScript testing promise

I'm trying to test a function which recives a promise like this
{
state: 'fulfilled'
value:[Array]
}
function register (foo) {
return new Promise((resolve,reject)=>{
query = "INSERT IGNORE INTO....";
connection.query(query, [foo.value.from, foo.value.id], (err, res, fields) => {
if(err){
return undefined //this will change
}
return foo
})
})
}
The thing is I am returning, non rejecting neither resolving. So when Im testing..
it('insertion error', function () {
var res = 'error'
connection = {
query: (query, input, cb) =>{
return cb(res, null, null)
}
}
let database = proxyquire('path/to',{
'./connection': connection
})
var input =
{
value: {
id: 'bar',
data: [],
from: 'foo'
}}
return database.register(input)
.then( (result) => {
expect(result).to.be.undefined
})
.catch( (err) => {
console.log(err)
err = new Error (`Test fail: ${err}`)
throw err;
})
})
The function works well, Im pretty sure of that.
The other thing I'm sure of is that the THEN/CATCH condition never shows up. I know if I replace the return for resolve it will show up, but I need to be returned.
What should I modify, or how should I test it.
This is a basic example how can you make a promisse, in this example you can send true or false in the register() function.
function register ( foo ) {
return new Promise( (resolve, reject) =>{
if(foo){
resolve('Done');
}else{
reject('Error')
}
} )
}
register(false).then( result=>{
document.write('promisse success... ', result);
} ).catch( error => {
document.write('promisse error... ', error);
} )

Node.js Mongoose Promise getting lost

I have a Node.js API with a mongoDB. There is a route that creates a user and needs to hash the password, for this I use the bcryptjs package.
the route looks like this:
router.route('/user')
.post(function(req, res) {
if(req.body.password === req.body.passwordConfirm) {
userManager.addUser(req.body)
.then(function(response) { // waiting for the result of the mongoDB save
res.send({data:response});
});
} else {
res.send({err:'passwords do not match'});
}
})
and userManager.addUSer:
this.addUser = function(userobject) {
bcrypt.genSalt(10, function(err, salt) { // generate a salt
if(err !== null) {
console.log(err);
} else {
bcrypt.hash(userobject.password_hash, salt, function(err, hash) { // hash pw
if(err !== null) {
console.log(err);
else {
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save().catch(function(err){ // save user in mongoDB
console.log(err);
});
}
});
}
});
};
I get an error saying: "Cannot read property 'then' of undefined", which tells me that I am not receiving a promise from addUser. I looked and bcryptjs sadly does not use promises, however, mongoose does.
(adding this:
var mongoose = require('mongoose').Promise = Promise;
didn't help)
I tried wrapping the function in a promise with reject and resolve, but that gives this error: "TypeError: Promise resolver undefined is not a function".
How do I get the promise that the save() function of mongoose returns back to the .then() in the post route? I tried adding return in front of the two bcrypt function but that didn't work either..
Any suggestions are welcome!
Your addUser function nevers returns the promise to its caller. You're doing a return from the bcrypt.hash callback function, but that has nothing to do with addUser's return value.
It looks like addUser has to use some non-Promise-enabled APIs, so you're stuck with doing new Promise, something like this (see the *** comments):
this.addUser = function(userobject) {
return new Promise(function(resolve, reject) { // ***
bcrypt.genSalt(10, function(err, salt) { // generate a salt
if(err !== null) {
reject(err); // ***
} else {
bcrypt.hash(userobject.password_hash, salt, function(err, hash) { // hash pw
if(err !== null) {
reject(err); // ***
else {
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
resolve(user.save()); // *** save user in mongoDB
}
});
}
});
});
};
Also note that I don't have addUser just swallowing errors; instead, they're propagated to the caller. The caller should handle them (even if "handling" is just logging).
You do not return a Promise form your this.addUser, you have to convert your callback based bcrypt to Promises. You can convert the whole bcrypt API to support Promise based functions using e.g. promisifyAll of the bluebird library, or do it manually using new Promise like this way:
this.addUser = function(userobject) {
return new Promise((resolve, reject) => {
bcrypt.genSalt(10, (err, salt) => {
if (err) {
reject(err);
} else {
bcrypt.hash(userobject.password_hash, salt, function(err, hash) {
if (err) {
reject(err)
} else {
resolve(hash)
}
})
}
});
})
.then(hash => {
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save() // save user in mongoDB
})
.catch(function(err) {
console.log(err);
});
}
Or that way:
this.addUser = function(userobject) {
return new Promise((resolve, reject) => {
bcrypt.genSalt(10, (err, salt) => {
if (err) {
reject(err);
} else {
resolve(salt);
}
});
})
.then(salt => {
return new Promise((resolve, reject) => {
bcrypt.hash(userobject.password_hash, salt, function(err, hash) {
if (err) {
reject(err)
} else {
resolve(hash)
}
})
})
})
.then(hash => {
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save() // save user in mongoDB
})
.catch(function(err) {
console.log(err);
});
}
After doing some more digging in the change logs of bcryptjs I found out that they added promises but did not update the documentation.. The genSalt en hash methods will return a promise if the callbacks are omitted. This would translate to:
this.addUser = function(userobject) {
return bcrypt.genSalt(10).then((salt) => {
return bcrypt.hash(userobject.password, salt).then((hash) => {
userobject.password_hash = hash;
var user = new User(userobject);
return user.save();
});
});
};

Categories