node/express server. parameter is undefined - node.js

What is going wrong with my string parameter?
var express = require('express');
var app = module.exports = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var braintree = require("braintree");
Schema = mongoose.Schema;
var user = require('../shared/userFunctions.js')
//register functions
app.register = function(api) {
api.get('get_client_token', generateClientToken);
api.get('find_customer', findCustomer);
api.post('checkout', checkout);
api.post('create_customer', createCustomer);
api.post('create_payment_method', newPaymentMethod);
}
The checkout function is where I call the local function with user.getuser
function checkout(request, response) {
var email = request.body.email;
var nonce = request.body.payment_method_nonce;
//var nonce = req.param("payment_method_nonce");
var amount = request.body.amount;
// Use payment method nonce here
gateway.transaction.sale({
amount: amount,
paymentMethodNonce: nonce,
}, function (err, result) {
if(err){
return response.send(500, "Checkout failed")
}
/* request.add({"amount": 10})
request = nonce;
newPaymentMethod(request);*/
/* return res.send(200, "Checkout Success")*/
});
user.getuser(email, function(u){
console.log("returning user: " + JSON.stringify(u))
return response.send(200, JSON.stringify(u))
})
}
If I hard core the email address into the mongoose query, it returns the user. What gives? Please give advice on my node async style. I am still new to it, but sometimes error first fucntions don't work and sometimes I need "next". The static email works but is my style the problem?
exports.getuser = function(email, res) {
var db = mongoose.connection;
mongoose.connect(process.env.MongoConnectionString);
db.on('error', function () {
});
db.once('open', function callback() {
console.log("Sucessfully Logged into mongo");
User.findOne({email:email}, function (err, user, next) {
if (err) {
mongoose.disconnect();
return next(err);
}
mongoose.disconnect();
console.log("Sending user response");
if(!user){
console.log("failed to get user")
return
}
return res(user);
});
});
EDIT
This function is responsible for calling the internal function. It seems to work exactly like the checkout function, except for its magical ability to work correctly.
function getUser(request, response) {
var email = request.param('email');
user.getuser(email, function(user){
return response.send(200, JSON.stringify(user))
})
};
Using a REST client so I assure you that body/params is not the problem. Thanks for the help thus far.

you can check your paratmeter in your api like this :
var password = req.body.passwordBrow || '';
var uidUser = req.body.uidUser || '';
and then check it :
if(password && uidUser){
// here you can log your parameters
}else{
// the parameter is undefined, so you need to check your request in the client
res.json({
status : "not_ok",
result : "empty_data",
resultType : serverConst.EmptyParams
});
}
hope it helps you.

Related

How to return data from a method that uses async functions?

I'm pretty new to using Express.js and I have an issue returning the data from the database query. The goal is to get user info from the table as JSON inside userController but only thing I get is undefined. I tried many different things but can't get my head around how to return the value from the method.
db.js
const mysql = require('mysql2');
var con = mysql.createPool({
//db data here
});
module.exports = con;
userController.js
var User = require("../models/userModel");
exports.registerUser = function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(u1.getInfo());
}
}
userModel.js
const db = require('../config/db');
module.exports = class User{
//constructor here
getInfo(){
try{
var query = "SELECT * FROM users";
db.query(query, function(err, data){
return JSON.stringify(data);
});
}
catch(err){
return err;
}
}
}
You are getting undefined because the query need to wait the answer, and when you call getInfo(), the return JSON.stringify(data); are only execute when the query have the data.
You can use promise warper, because you need to wait to the database response. To use promises mysql2 have this package: const mysql = require('mysql2/promise');
Make your getInfo() function asynchronous
async getInfo(){
try{
const res = await db.execute('SELECT * FROM users');
return res;
}
catch(err){
return err;
}
}
Then you can call the function with await:
exports.registerUser = async function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(await u1.getInfo());
}
I cant test the code now, but it should work

async await is not executing functions sequentially in express nodejs

I want to run 3 database query then render the 3 result objects to view, so I used async await to run queries first but seems its not waiting/working, always sending null objects to view before running queries. Cant find where I went wrong, I am using nodejs 12.16.1, not sure if its es6 supporting issue or sth else.
var express = require('express');
var router = express.Router();
var reviewModel = require.main.require('./models/review-model');
var propertyModel = require.main.require('./models/property-model');
router.get('/', async function(req, res){
try{
req.cookies['username'] == null ? loginCookie = null : loginCookie = req.cookies['username'];
var getPromoteInfo = await propertyModel.getPromoteInfo(function(result){
if(result!=null) return result;
});
var getPromoteReview = await reviewModel.getPromoteReview(function(result2){
if(result2!=null) return result2;
});
var getLatest3reviews = await reviewModel.getLatest3reviews(function(result3){
if(result3!=null) return result3;
});
res.render('index', {property:getPromoteInfo, rating:getPromoteReview, testimonials:getLatest3reviews, loginCookie});
}
catch(err){console.log(err);}
});
module.exports = router;
Model code:
var db = require('./db');
module.exports = {
getPromoteInfo: function(callback){
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
callback(result);
}else{
callback(null);
}
});
}
}
You're using await on a function that does not return a Promise resulting in an undefined value. So in order for async/await to work, you could rewrite getPromoteInfo as follows:
var db = require('./db');
module.exports = {
getPromoteInfo: function(){
return new Promise( (resolve, reject) => {
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
resolve(result);
}else{
// you can decide whether to reject or not if no records were found
reject();
}
});
});
}
}
In your express-handler you can then simply await this function call, without passing a callback:
const getPromoteInfo = await propertyModel.getPromoteInfo();
Note that you can check if your db-client/library supports promises out of the box - then you would not have to wrap your functions manually in a promise.

NodeJs login form with SQL Server user auth

I am having an issue with authenticating users using a SQL Server database. I have established the connection with the database and can pull user from the database. However when trying to query the database for authentication I get an "unhandledpromise - connection is closed" error.
app.js file:
var sql = require("mssql");
var express = require("express");
var session = require("express-session");
var bodyParser = require("body-parser");
var path = require("path");
var dbconfig = {
server: "Server",
database: "Test",
user: "########",
password: "####################",
port: 1433,
options : {
encrypt: false
}
};
var app = express();
app.use(session({
secret: 'Secret',
resave: true,
saveUninitalized: true
}));
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/login.html'));
});
app.post('/auth', function(request, response) {
var username = request.body.username;
var password = request.body.password;
var conn = new sql.ConnectionPool(dbconfig);
var req = new sql.Request(conn);
if (username && password) {
conn.connect();
req.query('Select * from Admin where username = ? and password = ?', [username, password], function(error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
resquest.session.username = username;
response.redirect('/home');
} else {
response.send('Username and/or Password not found');
}
conn.close();
response.end();
});
} else{
response.send('Please enter Username and Password');
}
});
app.get('/home', function(request, response){
if(request.session.loggedin){
response.send('Welcome back,' + request.session.username + '!');
}else{
response.send('Please sign');
}
response.end();
});
app.listen(3000);
function getEMP() {
var conn = new sql.ConnectionPool(dbconfig);
var req = new sql.Request(conn);
conn.connect(function(err) {
if (err) {
console.log(err);
return;
}
req.query("Select * from Admin", function(err, recordset) {
if (err) {
console.log(err)
} else {
console.log(recordset)
}
conn.close();
});
});
}
getEMP();
The getEMP function returns all of the admins from the database as expected. This is why I am positive the connection is working. This function was used for testing connection.
Error
UnhandledPromiseRejectionWarning: ConnectionError: Connection is closed.
at Request._query (///nodeconSQL/node_modules/mssql/lib/base/request.js:447:37)
at Request._query (///nodeconSQL/node_modules/mssql/lib/tedious/request.js:346:11)
at shared.Promise (///nodeconSQL/node_modules/mssql/lib/base/request.js:413:12)
at new Promise ()
at Request.query (///nodeconSQL/node_modules/mssql/lib/base/request.js:412:12)
at /home/devops-01/nodeconSQL/app.js:43:13
at Layer.handle [as handle_request] (///nodeconSQL/node_modules/express/lib/router/layer.js:95:5)
at next (///nodeconSQL/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (///nodeconSQL/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (///nodeconSQL/node_modules/express/lib/router/layer.js:95:5)
Your function getEMP() uses the callback from conn.connect() in order to wait until the connection is established before trying to execute the query.
The function that tries to login executes the query immediately after attempting to open the connection, however since the connection takes some time to be established, this is why you get the error that your connection is not open.
Put your login query inside the conn.connect(function(err){ /* login code */ }) construct like it is in your getEMP() function. You will then need to make sure that you can access the request and response objects in the callback function, for example by using .bind() on your callback function to put the request and response objects into the this object. Another option is to use closure functions to get data to the callbacks.
Example using closures:
app.post('/auth', function(request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
var conn = new sql.ConnectionPool(dbconfig);
conn.connect((function(){
var thisConn = conn;
var req = new sql.Request(thisConn);
return function(){ //connect callback
req.query('Select * from Admin where username = ? and password = ?', [username, password],
(function(){
var req = request;
var resp = response;
var conn = thisConn;
return function(error, results, fields) { // query callback
if (results.length > 0) {
req.session.loggedin = true;
req.session.username = username;
resp.redirect('/home');
} else {
response.send('Username and/or Password not found');
}
conn.close();
resp.end();
};
})());
};
})());
} else {
response.send('Please enter Username and Password');
}
});
Example using bind:
...
// Inside your /auth route
// make an object with the data our callback needs, to use with .bind()
var callbackData = {"conn": conn, "request": request, "response": response};
var connectCallback = function(err){
if (err) {
console.log(err);
return;
}
req.query('Select * from Admin where username = ? and password = ?',
[username, password], function(error, results, fields) {
// 2nd level of callback, query callback
if (results.length > 0) {
this.request.session.loggedin = true;
this.resquest.session.username = username;
this.response.redirect('/home');
} else {
this.response.send('Username and/or Password not found');
}
this.conn.close();
this.response.end();
}.bind(this)); // pass our 'this' object through to the next level
}.bind(callbackData);
conn.connect(connectCallback);
...

Using socket.io in modules and routes Express

I am having some issues using socket.io is modules. I have changed the way I do it quite drastically, however everything seems to be working, except being able to send userdata back to my socket connection:
Here is my io.js file: /config/io
/*jshint esversion: 6*/
var io = require('socket.io')();
const moment = require('moment');
// Socket stuff
io.on('connection', function (socket) {
socket.on('login', function (userdata) {
socket.handshake.session.userdata = userdata;
socket.handshake.session.save();
console.log(socket.handshake.session.userdata);
});
// Server Time
var interval = setInterval(function () {
var momentNow = moment();
var data = momentNow.format('LT');
socket.emit('time', data);
}, 60000);
// Chat - Needs work
socket.on('chat', function (msg) {
console.log(msg);
var username = 'Message'; //socket.handshake.session.userdata.username;
var message = '[' + moment().format('LT') + '] ' + username + ': ' + msg;
io.emit('message', message, username);
});
socket.on('disconnect', function () {
if (socket.handshake.session.userdata) {
delete socket.handshake.session.userdata;
socket.handshake.session.save();
}
console.log('user disconnected');
});
});
module.exports = io;
Here is where I'm trying to emit the data /config/passport: (please note that userdata does indeed contain the right information!)
/*jshint esversion: 6 */
const LocalStrategy = require('passport-local').Strategy;
const db = require('../config/db');
const bcrypt = require('bcryptjs');
var io = require('./io');
module.exports = function(passport) {
// Local Strategy login
passport.use(new LocalStrategy(function(username, password, done) {
// Match Username
let sql = 'SELECT * FROM users WHERE username = ?';
db.query(sql, [username], function(err, rows) {
if (err)
return done(err);
if (!rows.length) {
return done(null, false, {
type: 'loginMessage',
message: 'Wrong Login',
});
}
// Match Password
bcrypt.compare(password, rows[0].password, function(err, isMatch) {
if (err)
return done(err);
if (isMatch) {
var userdata = rows[0];
io.emit('login', userdata); // HERE IS WHERE I TRY TO EMIT IT
// console.log(rows[0]);
return done(null, rows[0]);
} else {
return done(null, false, {
type: 'loginMessage',
message: 'Wrong Login',
});
}
});
});
}));
Now here is my main app file: (leaving out a bunch of stuff)
var io = require('./config/io');
// Init App
const app = express();
// Init http server
const server = http.createServer(app);
// Attach IO
io.attach(server);
// Listen
server.listen(8080, function () {
console.log('Server listening on port 8080...');
});
Now, everything seems to be working fine, except being able to emit the data. Now I tried logging it client side as well (just in case it was emitting on client-side and not server-side) but it is not doing that as well.
Okay, so here is an actual working answer. It s a work-around, and I completely abandoned trying to do it from the passport login handler itself. But here is how I did it:
IO code:
var session = socket.handshake.session;
socket.on('login', function () {
if (socket.handshake.session.passport === undefined) {
var destination = '/';
socket.emit('not logged', destination);
} else {
console.log('user logged in');
var userId = session.passport.user;
var sql = 'SELECT * FROM users WHERE id = ?';
var query = db.query(sql, userId, function (err, rows) {
session.userdata = rows[0];
session.save();
var dataObj = session.userdata;
socket.emit('sart up', dataObj);
});
}
});
And jQuery:
// Connection Successful
socket.on('connect', function () {
connected = true;
socket.emit('login');
});
socket.on('disconnect', function () {
connected = false;
});
socket.on('not logged', function (destination) {
window.location.href = destination;
});
socket.on('start up', function (dataObj) {
});
I'm not a huge fan of having to do it this way, I would have liked to handle everything sever-sided, but for now this is working, and will use until I figure out how to do it the way I'd like to.

simple social network using node.js and mongodb

I am trying to build simple social network and I am following this book(Building Node Applications with MongoDB and Backbone)(https://github.com/Swiftam/book-node-mongodb-backbone/tree/master/ch10). However, I just realized that the node.js version has been updated.
I tied to solve some the issue however I got problem in chat.js that states this is the error:
ch10/routes/chat.js:27
data.sessionStore.load(data.sessionID, function(err, session) {
TypeError: Cannot read property 'load' of undefined
module.exports = function(app, models) {
var io = require('socket.io');
var utils = require('connect').utils;
var cookie = require('cookie');
this.io = io;
//var Session = require('connect').middleware.session.Session;
var sio = io.listen(app.server);
sio.configure(function() {
// Utility methods to see if the account is online
app.isAccountOnline = function(accountId) {
var clients = sio.sockets.clients(accountId);
return (clients.length > 0);
};
sio.set('authorization', function(data, accept) {
var signedCookies = cookie.parse(data.headers.cookie);
// var cookies = utils.parseSignedCookies(signedCookies, app.sessionSecret);
// data.sessionID = cookies['express.sid'];
data.sessionStore = app.sessionStore;
data.sessionStore.load(data.sessionID, function(err, session) {
if (err || !session) {
accept("Error", false);
} else {
data.session = session;
accept(null, true);
}
});
});
sio.sockets.on('connection', function(socket) {
var session = socket.handshake.session;
var accountId = session.accountId;
var sAccount = null;
socket.join(accountId);
io.use(function (socket, next) { next(); });
// Immediately trigger the login event
// of this account
app.triggerEvent('event:' + accountId, {
from: accountId,
action: 'login'
});
var handleContactEvent = function(eventMessage) {
socket.emit('contactEvent', eventMessage);
};
var subscribeToAccount = function(accountId) {
var eventName = 'event:' + accountId;
app.addEventListener(eventName, handleContactEvent);
console.log('Subscribing to ' + eventName);
};
// Find the account contacts and subscribe
models.Account.findById(accountId, function subscribeToFriendFeed(account) {
var subscribedAccounts = {};
sAccount = account;
account.contacts.forEach(function(contact) {
if (!subscribedAccounts[contact.accountId]) {
subscribeToAccount(contact.accountId);
subscribedAccounts[contact.accountId] = true;
}
});
// Subscribed to my feed as well
if (!subscribedAccounts[accountId]) {
subscribeToAccount(accountId);
}
});
// Remove listeners if socket disconnects
socket.on('disconnect', function() {
sAccount.contacts.forEach(function(contact) {
var eventName = 'event:' + contact.accountId;
app.removeEventListener(eventName, handleContactEvent);
console.log('Unsubscribing from ' + eventName);
});
app.triggerEvent('event:' + accountId, {
from: accountId,
action: 'logout'
});
});
var cookieParser = require('cookie-parser')(SESSION_SECRET);
// ### Cookie parser
// Wrapper arround Express cookie parser, so we can use the same cookie parser for socket.io.
// Parse Cookie header and populate `socket.request.cookies` with an object keyed by the cookie names.
// Uses signed cookies by passing a secret string, which assigns `socket.request.secret` so it may be used by other middleware.
function cookieParserWrapper (socket, next) {
// request, response and callback
cookieParser(socket.request, {}, next);
}
// Handle incoming chats from client
socket.on('chatclient', function(data) {
sio.sockets.in(data.to).emit('chatserver', {
from: accountId,
text: data.text
});
});
});
});
}
Without testing the code myself or anything.
"TypeError: Cannot read property 'load' of undefined"
That particular error means that data.sessionStore is undefined and that "load" does not exists as a property, since there is literally nothing defined in data.sessionStore.
So the problem in my opinion is that your session system is not working properly. Hope that helps a bit!

Resources