how to handle synchronous databse query in node.js - node.js

I am new to node.js, and I am starting with login and signUp implementation, and I have just found that my database Query of MySQL failed to execute in sequence. So what I do is to find does username match exisiting usernames in database, and invitation codes, if there exist, I will send my JSON file with property true, otherwise false, but I have just found, the json file is sent before the database query is finished, so that even if user name matched, the response property is still set to false. I tried async and sync but I still have trouble understanding and fixing my error, can someone please help me on fix or a better alternative implementation in this case? Thank you!!
Here is my code:
// build up connection to db
const con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'pwd',
database: 'test'
});
// async function search
async function dbFind(db, dbName, attribute, value) {
let users;
try{
console.log(`11111111111111`)
const users = await db.promise().query(`SELECT EMAIL_ADRESS FROM ${dbName} WHERE ${attribute} = ?`, [value]);
// console.log(`users: ${users}`)
if (users) {
return users;
} else {
return null;
}
} catch (err){
console.log(err)
}
}
// parse the json file from front-end and save it in variable data
app.post('/API/user/registration', function(req,res){
con.connect((err) => {
if(err){
console.log(err);
return;
}
console.log('Connection established');
});
var username = req.body.username;
var password = req.body.password;
var invicode = req.body.invitation_code;
var name = req.body.name;
console.log('reqeust ' + req.body)
// variable initialization
var invitationCodeMatched = false;
var role = 'student';
const uid = uuid.v4();
var verifyToken = uuid.v1()
var flag = true;
// // check if the username have already been registered isRegistered
if (dbFind.sync(con, 'login_Authentication', 'EMAIL_ADRESS', username) != null){
flag = false
} else {
flag = true
}
console.log(`1 ${flag}`)
// check invitation code to see if a user qualify for a TA:
if (dbFind(con, 'invitation_code', 'INVITATION_CODE', invicode) != null){
role = 'TA';
invitationCodeMatched = true
}
console.log(`3 ${invitationCodeMatched}`)
// otherwisr: insert it into te database:
const uLoginAuth = {
USER_ID: uid,
EMAIL_ADRESS: username,
PSWORD:password,
VERIFIED: false,
VERIFYCODE: verifyToken
};
const uInfo = {
USER_ID: uid,
NME: name,
USER_ROLE: role,
EMAIL_ADRESS: username
};
if(flag){
con.query('INSERT INTO login_authentication SET ?', uLoginAuth, (err, res) => {
if(err) throw err;
console.log('Last insert ID:', res.insertId);
});
con.query('INSERT INTO user_info SET ?', uInfo, (err, res) => {
if(err) throw err;
console.log('Last insert ID:', res.insertId);
});
}
con.query('SELECT * FROM user_info', (err,rows) => {
if(err) throw err;
console.log('Data received from Db:');
console.log(rows);
});
con.end((err) => {
// The connection is terminated gracefully
// Ensures all remaining queries are executed
// Then sends a quit packet to the MySQL server.
});
//send json file to the front end
console.log(`2 ${flag}`)
let judge = {
isRegistered: flag,
invitationCodeMatched: invitationCodeMatched
};
res.json(judge);
//If the user has not yet verified:
lib.sendConfirmationEmail(name, username, verifyToken)
});
app.listen(3000)
The output while hearing from request is:
1 false
2 false
and there is no output of 11111111 inside async dbFind function, there is a database match in this scenario, but what it returns is :
{
"isRegistered": false,
"invitationCodeMatched": false
}
which is the default value that is initailized before.

Related

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);
...

discord.js/node/mysql : how to wait until query returns result

I'm currently trying to write a bot for several Discord servers.
The problem is, that the code doesn't wait for the database to return the results. In the current situation, I'm trying to check if the author id of a message is already in the mysql database.
I read some stuff about async/await but I need your help to understand how to link these things together !
const Discord = require('discord.js');
var mysql = require('mysql');
// Discord client
const client = new Discord.Client();
// Load config file
const config = require('./config.json');
client.config = config;
// Database config
const connection = mysql.createConnection({
host: config.mysqlHost,
user: config.mysqlUser,
password: config.mysqlPassword,
database: config.mysqlDatabase
});
// Check if ownerId is already in database
function checkOwnerId(authorId) {
var query = connection.query(
'SELECT * FROM guilds WHERE ownerId = ?',
authorId,
function (error, results, fields) {
// Handle error after the release.
if (error) throw error;
// Debug
console.log(query.sql);
// If match
if (results.length > 0) return "verified";
else return "not_verified";
});
}
/*
* Event will run on every single message received, from any channel or DM.
*/
client.on('message', async msg => {
// Ignore any message that does not start with prefix and ignore itself
if (!msg.content.startsWith(config.prefix) || msg.author.bot) return;
// Verify in database if the author.id is already saved
if (checkOwnerId(msg.author.id) === "not_verified") {
// Delete the command line
msg.delete();
// Send pm to author with error
msg.author.send(
{embed: {
color: 15934014,
description: 'No permission to use the bot'
}
});
console.log("NOT VERIFIED");
return;
}
else {
// Continue
}
});
// Discord bot token
client.login(config.token);
How to verify in a database if the author id is already saved and after let him to use some commands ? Thank you in advance for your help !
You could do something like this, which will also allow you to make further SQL queries and work with the results:
const Discord = require('discord.js');
var mysql = require('mysql');
// Discord client
const client = new Discord.Client();
// Load config file
const config = require('./config.json');
client.config = config;
// Database config
const connection = mysql.createConnection({
host: config.mysqlHost,
user: config.mysqlUser,
password: config.mysqlPassword,
database: config.mysqlDatabase
});
// Check if ownerId is already in database
function sqlQuery(query, params) {
return new Promise((resolve, reject) => {
connection.query(
query, params,
(error, results) => {
if (error) return reject(error);
return resolve(results);
});
});
}
/*
* Event will run on every single message received, from any channel or DM.
*/
client.on('message', msg => {
// Ignore any message that does not start with prefix and ignore itself
if (!msg.content.startsWith(config.prefix) || msg.author.bot) return;
// Verify in database if the author.id is already saved
sqlQuery('SELECT * FROM guilds WHERE ownerId = ?', msg.author.id,)
.then(results => {
if (results.length > 0) {
//do stuff with verified user
} else {
msg.delete();
// Send pm to author with error
msg.author.send(
{embed: {
color: 15934014,
description: 'No permission to use the bot'
}
});
}
})
.catch(error => {
//handle error
});
});
// Discord bot token
client.login(config.token);

why mongoose queries dos not work when put inside promise function

My code is as shown below:
checkAndCreateUser(customer_id, email_id).then(result => {
console.log("result is " + result);
});
var checkAndCreateUser = function (custom_id, email) {
return new Promise(function (resolve, reject) {
if ((!custom_id) && (custom_id.trim() == '')) {
var creatUser = new user();
// creatUser._id = user_id;
creatUser.ph_no = ph_no;
creatUser.email_id = email;
console.log("fn works");
user.findOne({
'email_id': email
}, function (err, user) {
console.log("db test");
if (!user) {
creatUser.save(function (err, userInfo) {
if (err) {
reject("no id found");
} else {
customer_id = userInfo._id;
resolve(customer_id);
}
});
} else {
customer_id = user._id;
resolve(customer_id);
}
});
}
});
}
Now what happens here is I am not able to successfully run db query. I am able to get console.log("fn works") printed , but it does not print console.log("db test"). So what exactly is going wrong?
You forgot save your user, besides Mongoose already returned promise, you don't need use callbacks:
var checkAndCreateUser = function (custom_id, email) {
return User.create({ ph_no :ph_no,
email_id :email})
.then(result=>{
return User.findOne({'email_id': email})
})
.then(user=>{
return user._id;
})
};
As for mistake in your function:
...
let user = new User({email_id: email, ph_no: phone});
user.save();//you forgot about this
...
You can use save() with callback:
user.save((err, result)=>{...});
Or with promise:
user.save().then(result=>{...}).catch(err=>{...});

node/express server. parameter is undefined

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.

Server not responding to url with parameters

I'm attempting to create a server for now should be able to register users.
However the server doesn't react when attempting to register using /reg.
When I create a new .get it does respond though, so the server itself is working.
What also is unclear to me is how to correctly format the url.
app.post('/reg/:uname/:teamid', function(req, res){
var username = req.params.uname;
var teamidpar = req.params.teamid;
UserSchema.pre('save', function (next) {
this1 = this;
UserModel.find({uname : this1.username}, function(err, docs) {
if (!docs.length) {
//Username already exists
} else {
var loginid = randomstring.generate();
var newUser = User({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
User.save(function (err, User, next) {
if (err) {return console.error(err);}
else
{console.log(timestamp+':'+'User created:'+newUser.uname+':'+newUser.login);}
res.json({login : loginid});
});
}
});
});
});
I don't know why I didn't see this earlier, but you use UserSchema.pre at the beginning, however this is just a definition and will not be immediately executed. Only when you actually do a save on a document will this function be triggered.
Below the correct, edited version.
app.post('/reg/:uname/:teamid', function(req, res) {
var username = req.params.uname;
var teamidpar = req.params.teamid;
// If you are just checking if something exist, then try count
// as that has minimal impact on the server
UserModel.count({uname : username}, function(err, count) {
if (count > 0) {
// Username already exists, but always output something as we
// don't want the client to wait forever
return res.send(500);
}
var loginid = randomstring.generate();
// You'll need a new instance of UserModel to define a new document
var newUser = new UserModel({
uname : username,
teamid : teamidpar,
totalscore : 0,
lastopponement : null,
gamescore : 0,
});
// Save the document by calling the save method on the document
// itself
newUser.save(function (err) {
if (err) {
console.error(err);
// You'll want to output some stuff, otherwise the client keeps on waiting
return res.send(500);
}
console.log(timestamp + ': User created:' + username + ':' + loginid);
res.json({login : loginid});
});
});
});

Resources