Use ldapjs with bluebird promise - javascript

I posted something similar here: Use ldapjs with promise. Unfortunately, it is still unsolved.
This time I tried bluebird and hopefully I can get some luck.
// https://www.npmjs.com/package/ldapjs
var Promise = require('bluebird');
var ldap = Promise.promisifyAll( require('ldapjs') );
var config = require('./config');
var print_r = require('print_r').print_r;
var my_filter = "(&(objectCategory=person)(objectClass=user)" + "(cn=" + 'someone' + "))";
var ldap_username = config.ad.username;
var ldap_password = config.ad.password;
var ldap_url = config.ad.url;
var ldap_dn_search = config.ad.dn_search;
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var opts = {
filter: my_filter,
scope: 'sub',
};
//test
console.log(my_filter);
console.log(ldap_username);
console.log(ldap_password);
console.log(ldap_url);
console.log(ldap_dn_search);
/* NOTE: This code is working!!!
client.bind(ldap_username, ldap_password, function (err) {
client.search(ldap_dn_search, opts, function (err, search) {
search.on('searchEntry', function (entry) {
var user = entry.object;
console.log(user);
});
});
});
*/
// I tried to rewrite the code above with promise
ldap.createClientAsync({
url: ldap_url
})
.then(function(client){
console.log('bind'); // No print
return client.bindAsync(ldap_username, ldap_password);
})
.then(function() {
console.log('search'); // No print
return client.searchAsync(ldap_dn_search, opts);
})
.then(function(search) {
// No flow here
search.on('searchEntry', function (entry) {
var user = entry.object;
console.log(user);
});
})
The script doesn't output anything. It is waiting for something in terminal.

Using Bluebird Promises, the easy way to do this is to create your client normally, and then run the promisifyAll() on the client.
var ldap = require('ldapjs');
var Promise = require('bluebird');
var client = ldap.createClient({
url: 'ldap://my-server:1234',
});
Promise.promisifyAll(client);
Now you can call client.addAsync() and client.searchAsync() and such.
client.bindAsync(secUserDn, secUserPassword)
.then(doSearch) // if it works, call doSearch
.catch(function (err) { // if bind fails, handle it
console.error('Error on bind', err)
});
function doSearch(data) {
client.searchAsync('CN=A Test,OU=Users,DC=website,DC=com', options)
.then(function (data) { // Handle the search result processing
console.log('I got a result');
})
.catch(function (err) { // Catch potential errors and handle them
console.error('Error on search', err);
});
}

Related

Problem using async functions in NodeJs middleware

I am running into an issue when I try to load the initial data for my blacklist from a Redis DB in my middleware code. Since the DB request takes some time it starts to fail.
Below is my code which gets fired when app starts via app.use(blacklist.blockRequests());.
When I try to make the function async I get the error that new TypeError('app.use() requires a middleware function').
One of the side effects is also that my array is empty when it's called again.
blockRequests: function() {
this.read();
this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
var self = this;
var interceptor = function(request, response, next) {
var ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
if (self.isInBlacklist(ip)) {
self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
response.status(403).send();
} else {
next();
}
}
return interceptor;
},
And here is my read() function code:
read: function() {
try {
// get all records with prefix block:: from redis
redis.redis.keys('block::*', function (err, reply) {
// reply is null when the key is missing
if(err){}
else {
this.blacklist = []
for (let i = 0; i < reply.length; i++) {
let ipInt = reply[i].substring(7)
let ipStr = ipToInt(ipInt).toIP()
this.blacklist.push(ipStr)
}
}
});
} catch (error) {
if (error) {
this.blacklist = [];
}
}
}
If you're trying to make blockRequests() async, then it will start returning a promise and you can't use its return value directly in app.use(). Because then you'd be doing app.use(somePromise) and Express will balk because you have to pass it a function reference, not a promise.
Instead, you will have to use .then() or await to get the return value which is the function which you could then use with app.use().
If you show the larger calling context here (like where you're calling blockRequests() from), then we could offer more ideas on a fuller solution.
Here's a conceptual idea for how you could do this:
blockRequests: function() {
const self = this;
const interceptor = function(request, response, next) {
const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
if (self.isInBlacklist(ip)) {
self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
response.status(403).send();
} else {
next();
}
}
return interceptor;
},
read: function() {
// get all records with prefix block:: from redis
return new Promise((resolve, reject) => {
redis.redis.keys('block::*', (err, reply) => {
if (err) {
this.blacklist = [];
reject(err);
} else {
this.blacklist = [];
for (let i = 0; i < reply.length; i++) {
let ipInt = reply[i].substring(7)
let ipStr = ipToInt(ipInt).toIP()
this.blacklist.push(ipStr)
}
}
this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
resolve();
});
});
}
// register middleware for using blacklist
app.use(blacklist.blockRequests());
// now read the blacklist and when that is in place, then start the server
blacklist.read().then(() => {
// now we know that blacklist.blacklist is up-to-date
// start your server here
}).catch(err => {
console.log("Unable to start server - error in reading blacklist");
process.exit(1);
});

How to access await function variable outside function in Node.js

I am trying to implement an await function which local variable I am trying to access outside the function. However, I'm not getting the value which is defined inside function.
async CreateProduceRateAsset(data, callback) {
// Create a new file system based wallet for managing identities.
try {
var TimeStamp = new Date();
var TxId = '';
var blockNumber = '';
const result = await contract.submitTransaction('CreateProduceRateAsset', args);
await network.addBlockListener('block-listener', (err, block) => {
if (err) {
console.log(err);
return;
}
TimeStamp = block.data.data[0].payload.header.channel_header.timestamp;
var Tx_id = block.data.data[0].payload.header.channel_header.tx_id;
var BlockNO = block.header.number;
console.log('TxId', Tx_id)
console.log('blockNumber', BlockNO)
TxId = Tx_id
blockNumber = BlockNO
return TimeStamp, Tx_id, BlockNO
});
console.log('Timestamp', TimeStamp)
console.log('TxId 123', TxId)
console.log('blockNumber 123', blockNumber)
response.data = result
return callback(response);
} catch (error) {
response.httpstatus = 404;
response.message = `Failed to get MVP Price ${error.message} `;
return callback(response);
}
};
In the above code, I want to access Tx_id, Timestamp and BlockNO. For that, I am assigning a local variable to a global variable, however, I'm still getting the value of those as blank.
Could someone help me to get those values?
if I understand network.addBlockListener is a callback-based API and not return a promise so you cant await it, I guessed that you use https://hyperledger.github.io/fabric-sdk-node/release-1.4/module-fabric-network.Network.html
Here is your code with my comments
async CreateProduceRateAsset(data, callback) {
// Create a new file system based wallet for managing identities.
try {
var TimeStamp = new Date();
var TxId = '';
var blockNumber = '';
const result = await contract.submitTransaction('CreateProduceRateAsset', args);
// --> this api is callback based and wont not return a promise so you cant await it
await network.addBlockListener('block-listener', (err, block) => {
if (err) {
console.log(err);
return;
}
TimeStamp = block.data.data[0].payload.header.channel_header.timestamp;
// --> becasue you are inside a function these vars are not the same as the one ouside the call back , becasue they are scoped to this function
var Tx_id = block.data.data[0].payload.header.channel_header.tx_id;
var BlockNO = block.header.number;
console.log('###########TxId#####################', Tx_id)
console.log('###########blockNumber#####################', BlockNO)
TxId = Tx_id
blockNumber = BlockNO
// --> you can only return one value in js, also this reurn is useless since you dont call this callback
// --> better way to get these vars outside the callback is to pass them to your own callbak like this `callback(response,TimeStamp, Tx_id, BlockNO)`
return TimeStamp, Tx_id, BlockNO
});
console.log('*************** Timestamp:: **********************', TimeStamp)
console.log('###########TxId#####################123', TxId)
console.log('###########blockNumber#####################123', blockNumber)
response.data = result
return callback(response);
} catch (error) {
// if(error) throw error;
// response.error = error;
response.httpstatus = 404;
response.message = `Failed to get MVP Price ${error.message} `;
return callback(response);
}
};
if you need to use async/await with network.addBlockListener you can use utils.promisify to convert it to promise-based API but I don't recommend it since this an event listener
You have to put your return into a variable like this:
var data = await network.addBlockListener('block-listener', (err, block) => {
if (err) {
console.log(err);
return;
}
TimeStamp = block.data.data[0].payload.header.channel_header.timestamp;
var Tx_id = block.data.data[0].payload.header.channel_header.tx_id;
var BlockNO = block.header.number;
console.log('###########TxId#####################', Tx_id)
console.log('###########blockNumber#####################', BlockNO)
TxId = Tx_id
blockNumber = BlockNO
return {TimeStamp, Tx_id, BlockNO};
});
console.log('*************** Timestamp:: **********************', data.TimeStamp)
console.log('###########TxId#####################123', data.Tx_id)
console.log('###########blockNumber#####################123', data.BlockNO)
Now you can store all your values into data and put them into the desired variables.

Node.js mssql return query result to ajax

I'm new to learning Node.js, so I'm still getting used to asynchronous programming and callbacks. I'm trying to insert a record into a MS SQL Server database and return the new row's ID to my view.
The mssql query is working correctly when printed to console.log. My problem is not knowing how to properly return the data.
Here is my mssql query - in addJob.js:
var config = require('../../db/config');
async function addJob(title) {
var sql = require('mssql');
const pool = new sql.ConnectionPool(config);
var conn = pool;
let sqlResult = '';
let jobID = '';
conn.connect().then(function () {
var req = new sql.Request(conn);
req.query(`INSERT INTO Jobs (Title, ActiveJD) VALUES ('${title}', 0) ; SELECT ##IDENTITY AS JobID`).then(function (result) {
jobID = result['recordset'][0]['JobID'];
conn.close();
//This prints the correct value
console.log('jobID: ' + jobID);
}).catch(function (err) {
console.log('Unable to add job: ' + err);
conn.close();
});
}).catch(function (err) {
console.log('Unable to connect to SQL: ' + err);
});
// This prints a blank
console.log('jobID second test: ' + jobID)
return jobID;
}
module.exports = addJob;
This is my front end where a modal box is taking in a string and passing it to the above query. I want it to then receive the query's returned value and redirect to another page.
// ADD NEW JOB
$("#navButton_new").on(ace.click_event, function() {
bootbox.prompt("New Job Title", function(result) {
if (result != null) {
var job = {};
job.title = result;
$.ajax({
type: 'POST',
data: JSON.stringify(job),
contentType: 'application/json',
url: 'jds/addJob',
success: function(data) {
// this just prints that data is an object. Is that because I'm returning a promise? How would I unpack that here?
console.log('in success:' + data);
// I want to use the returned value here for a page redirect
//window.location.href = "jds/edit/?jobID=" + data;
return false;
},
error: function(err){
console.log('Unable to add job: ' + err);
}
});
} else {
}
});
});
And finally here is the express router code calling the function:
const express = require('express');
//....
const app = express();
//....
app.post('/jds/addJob', function(req, res){
let dataJSON = JSON.stringify(req.body)
let parsedData = JSON.parse(dataJSON);
const addJob = require("../models/jds/addJob");
let statusResult = addJob(parsedData.title);
statusResult.then(result => {
res.send(req.body);
});
});
I've been reading up on promises and trying to figure out what needs to change here, but I'm having no luck. Can anyone provide any tips?
You need to actually return a value from your function for things to work. Due to having nested Promises you need a couple returns here. One of the core features of promises is if you return a Promise it participates in the calling Promise chain.
So change the following lines
jobID = result['recordset'][0]['JobID'];
to
return result['recordset'][0]['JobID']
and
req.query(`INSERT INTO Jobs (Title, ActiveJD) VALUES ('${title}', 0) ; SELECT ##IDENTITY AS JobID`).then(function (result) {
to
return req.query(`INSERT INTO Jobs (Title, ActiveJD) VALUES ('${title}', 0) ; SELECT ##IDENTITY AS JobID`).then(function (result) {
and
conn.connect().then(function () {
to
return conn.connect().then(function () {
You may need to move code around that is now after the return. You would also be well served moving conn.close() into a single .finally on the end of the connect chain.
I recommend writing a test that you can use to play around with things until you get it right.
const jobId = await addJob(...)
console.log(jobId)
Alternatively rewrite the code to use await instead of .then() calls.

Node.js Async Promises within a forEach Loop inside another then statement

I have been trying to understand promises nesting with this simple code.
Both functions that I'm calling are async, one giving an entire collection and the other just individual information of each of the elements.
What am I doing wrong?
const PirateBay = require ('thepiratebay');
var os = require ('os');
var sys = require('util');
var util = require('util');
var cfg = require('./config/appconf.js');
var mysql = require('mysql');
var Torrent = require('./models/torrent.js');
var parseTorrent = require('parse-torrent')
var async = require('async');
function saveResults (results) {
console.log( "Save Results");
var cTorrents = [];
for (var key in results) {
var t =results[key];
var torrent = new Torrent()
torrent.id = t.id;
torrent.name = t.name;
torrent.size = t.size;
torrent.seeders = t.seeders;
torrent.leechers = t.leechers;
torrent.verified = t.verified;
torrent.uploader = t.uploader;
torrent.category = t.category.name;
torrent.description = t.description;
torrent.subcategory = t.subcategory.name;
var r = parseTorrent (t.magnetLink);
torrent.announce = r.announce;
torrent.hash = r.infoHash;
cTorrents.push (torrent);
}
return cTorrents;
}
PirateBay
.recentTorrents()
.then( function(results){
var lTorrents = saveResults(results);
async.each (lTorrents,function (t,next){
await PirateBay
.getTorrent(t.id)
.then(function (err, doc){
console.log(doc.description);
t.doc = doc.description;
next();
});
},function (err) {
console.log ("WHNEEEEE");
console.log(lTorrents);
});
console.log(lTorrents);
})
.catch (function (err){
console.log(err);
});
You don't need the async module, Promise should be sufficient. In particular what you might be interested in is Promise.all() which takes an array of Promises and resolves when all promises finishes. Using Array.prototype.map() each element of lTorrents can be mapped into a Promise. Here's an example..
PirateBay
.recentTorrents()
.then(function(results){
var lTorrents = saveResults(results);
return Promise.all(lTorrents.map(function(t) {
return PirateBay.getTorrent(t.id)
.then(function(doc) {
t.doc = doc.description;
return t;
})
.catch(function(err) {
// if one request fails, the whole Promise.all() rejects,
// so we can catch ones that fail and do something instead...
t.doc = "Unavailable (because getTorrent failed)";
return t;
});
}));
})
.then(function(lTorrents) {
// do what you gota do..
})

Return from the function wasn't assigned to the $scope?

Here is my controller:
$scope.mainModel = getReviews({model:mainModelArr[1]});
$scope.compareModel = getReviews({model:compareModelArr[1]});
function getReviews(data) {
$http.post(url, data)
.success(function(res) {
formatReviews(res)
})
.error(function(err) {
console.log("Something went wrong: "+err);
});
}
function formatReviews(data) {
var review = data[0];
review.sumReviews = (review.sumReviews/review.ratingAvg).toFixed(0);
review.sumRecommend = (review.sumRecommend/review.sumReviews*100).toFixed(1);
review.ratingAvg = (review.ratingAvg).toFixed(1);
console.log(review); // logs message fine
return review;
}
These functions work fine, logs review var., but somehow it didn't assign review variable neither to $scope.mainModel nor to $scope.compareModel.
NOTE: I know that it wasn't assigned, because it's never showed up in HTML:
<p>{{mainModel}}</p>
What did I do wrong and how can I fix that?
Ajax requests works Async, angularjs use promises to handle this requests
$scope.mainModel = undefined;
$scope.compareModel = undefined;
getReviews({model:mainModelArr[1]}).success(function(res){
$scope.mainModel = formatReviews(res);
});
getReviews({model:compareModelArr[1]}).success(function(res){
$scope.compareModel = formatReviews(res);
});
If you return post request, you can handle it anywhere, where you call getReviews method
function getReviews(data) {
return $http.post(url, data)
.error(function(err) {
console.log("Something went wrong:", err);
});
}
function formatReviews(data) {
var review = data[0];
review.sumReviews = (review.sumReviews / review.ratingAvg).toFixed(0);
review.sumRecommend = (review.sumRecommend / review.sumReviews * 100).toFixed(1);
review.ratingAvg = (review.ratingAvg).toFixed(1);
console.log(review); // logs message fine
return review;
}
Since asynchronous code won't allow you simply return the value, you should work with promises using their then methods:
getReviews({model: mainModelArr[1]}).then(function(data) {
$scope.mainModel = data;
});
getReviews({model: compareModelArr[1]}).then(function(data) {
$scope.compareModel = data;
});
function getReviews(data) {
return $http.post(url, data)
.success(formatReviews)
.error(function(err) {
console.log("Something went wrong: "+err);
});
}

Categories