I followed the Keystone documentation for creating a new project. I'm trying to create a page that behaves differently based on whether the user is logged in or not.
My pug page it's something like that:
extends ../layouts/default
block content
if(!user)
.container: .jumbotron
.row
.col-md-2
.col-md-8.text-center.welcome
h2 Welcome
.col-md-2
else
.container: .jumbotron
.row
.col-md-2
.col-md-8.text-center.welcome
h2 Logged in
.col-md-2
.row
My index.js have this at the end, for expose the endpoints:
// Setup Route Bindings
exports = module.exports = function (app) {
// Views
app.get('/', routes.views.index);
app.all('/signin', routes.views.signin);
};
And the JavaScript file that serve the routing signin
endpoint is:
var keystone = require('keystone');
var User = keystone.list('User');
var bcrypt = require('bcrypt');
exports = module.exports = function (req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
var utente = req.body.utente;
var passwd = req.body.password;
// locals.section is used to set the currently selected
// item in the header navigation.
locals.section = 'home';
view.on('init', function(next){
next();
});
view.on('post', { action: 'signin' }, function (next) {
// console.log("utente: " + utente);
User.model.find()
.where('email', utente)
.exec()
.then(function (user) { //first promise fulfilled
//return another async promise
console.log("user: ", user);
console.log("email: ", user[0].email);
console.log("password: ", user[0].password);
bcrypt.compare(passwd, user[0].password, function(err, res) {
if(res){
console.log("Signin OK!");
locals.user = user[0];
}else{
console.log("Wrong Email or Password!");
req.flash("error", "wrong email or password!");
}
});
}, function (err) { //something happened
//catch the error, it can be thrown by any promise in the chain
console.log(err);
});
next();
});
// Render the view
view.render('index');
};
But my pug page doesn't recognize the user
variable, how it should be.
Instead if I move the next()
instruction more internally:
var keystone = require('keystone');
var User = keystone.list('User');
var bcrypt = require('bcrypt');
exports = module.exports = function (req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
var utente = req.body.utente;
var passwd = req.body.password;
// locals.section is used to set the currently selected
// item in the header navigation.
locals.section = 'home';
view.on('init', function(next){
next();
});
view.on('post', { action: 'signin' }, function (next) {
// console.log("utente: " + utente);
User.model.find()
.where('email', utente)
.exec()
.then(function (user) { //first promise fulfilled
//return another async promise
console.log("user: ", user);
console.log("email: ", user[0].email);
console.log("password: ", user[0].password);
bcrypt.compare(passwd, user[0].password, function(err, res) {
if(res){
console.log("Signin OK!");
locals.user = user[0];
}else{
console.log("Wrong Email or Password!");
req.flash("error", "wrong email or password!");
}
next();
});
}, function (err) { //something happened
//catch the error, it can be thrown by any promise in the chain
console.log(err);
next();
});
//next();
});
// Render the view
view.render('index');
};
Everything goes fine! And the user
variable is read correctly.
How it is possible? In these two pieces of code the position of the next()
function isn't equivalent???
They're definitely not equivalent. You have
aPromise
.then(function (user) { //first promise fulfilled
bcrypt.compare(passwd, user[0].password, function(err, res) {/*...*/});
next();
vs
aPromise
.then(function (user) { //first promise fulfilled
bcrypt.compare(passwd, user[0].password, function(err, res) {
/*...*/
next();
});
In your first one, next()
is executed before the promise is fulfilled, passwords compared, callback called, and locals.user
assigned a value. In your second one, it's executed after all of that has happened.