I've been struggling with promises and .then(), I have managed to create my two promises and they run, I think, however the ordering is still wrong, the first promise gets an updated spreadsheet and the next one does stuff to that spreadsheet and sends mails with that sheets data, no matter what I do I can't get the ordering to be correct. The message "Done fetching latest Drive sheet.." always prints after the mailing rules have run but it should be before. The getNewSheet promise should run, and then the sendMails promise should. Why isn't getNewSheet() running and then .sendMails?
Please help me understand why this isn't running and what I am doing wrong with the promises, additionally why isnt the message method of the promise return their values? I assume because the promise wasn't resolved in the correct order.
Please note I am still learning and using environment variables for some variables, I have edited out what I can, its a bit long but I am curious if I need to do something further with the containing code/functions in each promise before it would successful.
EDITED: Edited code to be more accurate.
let getNewSheet = function () {
return new Promise(function (resolve, reject) {
const fs = require("fs");
const readline = require("readline");
const {
google
} = require("googleapis");
const SCOPES = "https://www.googleapis.com/auth/drive";
const TOKEN_PATH = "token.json";
fs.readFile("credentials.json", (err, content) => {
if (err) return console.log("Error loading client secret file:", err);
authorize(JSON.parse(content), getLatestListFromDrive);
});
function authorize(credentials, callback) {
const {
client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]
);
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getAccessToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPES
});
console.log("Authorize this app by visiting this url:", authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Enter the code from that page here: ", code => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error("Error retrieving access token", err);
oAuth2Client.setCredentials(token);
fs.writeFile(TOKEN_PATH, JSON.stringify(token), err => {
if (err) console.error(err);
console.log("Token stored to", TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function getLatestListFromDrive(auth) {
const drive = google.drive({
version: "v3",
auth
});
var fileId = process.env.NODE_DRIVE_FILE_ID;
var dest = fs.createWriteStream("" + appDir + "\\tmp\\feedbacklist.xlsx");
drive.files.export({
fileId: fileId,
mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}, {
responseType: "stream"
},
function (err, res) {
res.data
.on("end", () => {
})
.on("error", err => {
console.log("Error", err);
})
.pipe(dest);
}
);
}
resolve();
});
};
var path = require("path");
var appDir = path.dirname(require.main.filename);
let sendMails = function () {
return new Promise(function (resolve, reject) {
const XLSX = require("xlsx");
const workbook = XLSX.readFile("" + appDir + "\\tmp\\feedbacklist.xlsx", {
type: "binary",
cellDates: true,
dateNF: "yyyy-mm-dd;#"
});
const SheetNameList = workbook.SheetNames;
var rows = XLSX.utils.sheet_to_json(workbook.Sheets[SheetNameList[0]], {
raw: false
});
var raw = workbook.Sheets[SheetNameList[0]];
var today = new Date();
today = today.toISOString().slice(0, 10);
var dateYesterday = new Date();
dateYesterday.setDate(dateYesterday.getDate() - 1);
dateYesterday = dateYesterday.toISOString().slice(0, 10);
var dayYesterday = new Date();
var days = [
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
];
dayYesterday.setDate(dayYesterday.getDate() - 1);
dayYesterday = days[dayYesterday.getDay()];
var dateTomorrow = new Date();
dateTomorrow.setDate(dateTomorrow.getDate() + 1);
dateTomorrow = dateTomorrow.toISOString().slice(0, 10);
var dayTomorrow = new Date();
var futureDays = [
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
];
dayTomorrow.setDate(dayTomorrow.getDate() + 1);
dayTomorrow = futureDays[dayTomorrow.getDay()];
var filteredRows = rows.filter(eachRow);
function eachRow(eachRow) {
return eachRow["tourDate"] === dateYesterday;
}
if (filteredRows != 0) {
for (x = 0; x < filteredRows.length; x++) {
console.log(filteredRows[x].emailAddress);
console.log(filteredRows[x].fName);
console.log(filteredRows[x].tourDate);
console.log(filteredRows[x].feedbacksent);
var nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
host: process.env.NODEMAILER_SERVICE,
secure: false,
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASS
}
});
var mailOptions = {
from: process.env.NODEMAILER_FROM,
to: "" + filteredRows[x].emailAddress + "",
subject: "Hi",
html: "Hi ",
text: "Hi "
};
console.log("I've sent a feedback request to " + filteredRows[x].emailAddress);
transporter.sendMail(mailOptions, function (error, info) {
//check for console errors
if (error) {
console.log(error);
} else {
console.log(
"Feedback request sent to " +
filteredRows[x].emailAddress
);
};
})
}
} else {
console.log("No rows/records to process for yesterday..");
}
resolve();
});
};
getNewSheet(console.log("drive fetched")).then(function (result) {
console.log("mails sent");
return sendMails(result);
}).then(function () {
console.log("promises finished");
});
Call resolve and reject functions when the operations you had scheduled, were actually completed.
Remember that when dealing with asynchronous operations, the code you write is executed out of order, meaning not in the order it is written in the file.
Consider these examples:
Will not work
return new Promise(function (resolve, reject) {
let result
fs.someAsyncOperation(function (data) {
result = data
})
resolve(result) // the promise will resolve immediately with undefined value
}
Will work
return new Promise(function (resolve, reject) {
fs.someAsyncOperation(function (result) {
resolve(result) // the promise will resolve after async operation is completed
})
}
Your code should be reworked to wait for the results of asynchronous operation before calling resolve function.
Under your sendMessage promise function, the resolve should be inside the callback of the sendMail function since it is asynchronous.
transporter.sendMail(mailOptions, function(error,info){
resolve();
});
UPDATE
Async stuff sometimes gets real tricky especially if you're used to synchronous processes. When I started on software this got me confused to.
You're promise functions are good. The problem there was that you were resolving the send function before it actually did it's job.
So below is a simpler version of your code. Doing the same thing you did
// function that returns a message
// duration: 1s
function getMessage() {
return new Promise(resolve => {
setTimeout(() => resolve('important message'), 1000)
});
}
// function that send a message using sendEmail function
// duration should be based on sendEmail
// notice that the resolve is called inside the callback
function sendMessage(message) {
return new Promise((resolve, reject) => {
sendEmail(message, (err, result) => {
// do some stuff if email was sent
})
resolve();
});
}
// function try to send an email asynchronously using a callback
// duration: 0.5s
function sendEmail(message, callback) {
setTimeout(() => {
console.log('email sent!')
callback(null, 'message sent');
}, 500)
}
getMessage().then(result => {
return sendMessage(result);
}).then(() => {
console.log('should be done after email')
})
With the above code your terminal should show
should be done after email
email sent!
But with some modification on the sendMessage function
function sendMessage(message) {
return new Promise((resolve, reject) => {
sendEmail(message, (err, result) => {
resolve(result);
})
});
}
The terminal should now show
email sent!
should be done after email
Related
I have been working on my first node.js backend and I am trying to refactor the login function, but i am not understanding something about promise chaining and error handling. I am hoping someone can help point out what I am missing here.
I have read about promise chaining and I understand that one catch should be able to handle any error in the chain, but I cant seem to get it to work without having an individual .catch for every .then
Here is my userLogin function.
const loginUser = handleAsync(async (req, res, next) => {
let userEmail = req.body.email;
let submittedPassword = req.body.password;
userLogin(userEmail, submittedPassword)
.then((userObject) => {
res.json(userObject);
})
.catch((err) => {
res.status(401).send(err);
console.log("any error inside userLogin: " + err);
});
});
async function userLogin(email, submittedPassword) {
console.log("in user login");
return new Promise(function (resolve, reject) {
getUserAccountByEmail(email)
.then((userAccountResults) => {
let email = userAccountResults[0].email;
let storedPassword = userAccountResults[0].password;
//the user exists check the password
//the user exists. Now Check password.
checkUserPassword(submittedPassword, storedPassword)
.then((passwordIsAMatch) => {
//The password is a match. Now Generate JWT Token.
generateJWTToken(email)
.then((tokens) => {
//build json object with user information and tokens.
createUserDataObject(tokens, userAccountResults)
.then((userObject) => {
//send the user object to the front end.
resolve(userObject);
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
});
}
And here is one of the functions that is a part of the chain
function getUserAccountByEmail(email) {
return new Promise(function (resolve, reject) {
logger.info("Looking up user email");
const users = User.findAll({
where: {
email: email,
},
limit: 1,
attributes: [
"email",
"password",
"userId",
"stripeConnectAccountId",
"isStripeAccountSet",
"stripeCustomerId",
],
})
.then((userResults) => {
if (doesUserExist(userResults)) {
resolve(userResults);
} else {
console.log("user doesnt exist in getuseraccount");
reject("User Email Does Not Exist In Database");
}
})
.catch((error) => {
console.log("Error Accessing Database: UserAccountByEmail");
logger.error("Error in getUserAccountByEmail: " + error);
});
});
}
Any help would be appreciated. Thanks
I took jfriend00 's advice and refactored using await instead of nesting.
async function userLogin(email, submittedPassword) {
return new Promise(async function (resolve, reject) {
try {
//Get User Account Information
const userAccountResults = await getUserAccountByEmail(email);
//Password Authentication
let storedPassword = userAccountResults[0].password;
const passwordIsAMatch = await checkUserPassword(
submittedPassword,
storedPassword
);
//Generate JWT Tokens
const tokens = await generateJWTToken(email);
//Prepare user data JSON for sending to the frontend.
const userData = await createUserDataObject(tokens, userAccountResults);
resolve(userData);
} catch (error) {
reject(error);
}
});
}
I am trying to save the file and details of it in the database.
Waterfall function with two calls but the second function is not waiting for the first function to finish.
Even without using waterfall eachseries doesn't work as expected. It doesn't wait for the record to be created and hence uniqueness error occurs due to same id.
What am I doing wrong here and how can I fix it?
Thanks!
async.eachSeries(uploadedPhotos, async function (uploadedFile, callback) {
async.waterfall([
async function() {
var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
// fileID remains undefined if i remove async-await from the function
var fileID = lastUser[0].id;
fileID += 1;
cbb(null, fileID, uploadedFile);
},
async function(file_id, uploadedFile, cbb) {
sails.log("save file id is " + file_id);
sails.log("savee file id is " + uploadedFile['filename']);
var today = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
await TblUserFiles.findOrCreate({ customer_no: req.session.userId, file_type: 'profile_image' }, {
id: fileID,
customer_no: req.session.userId,
file_name: uploadedFile['filename'],
file_type: 'profile_image',
is_approved: 'No',
approved_by: 0,
approved_on: today,
approved_from: ip,
uploaded_date: today,
modified_date: today
}).exec(async (err, user, wasCreated) => {
if (err) { return res.serverError(err); }
if (wasCreated) {
// created a new user
sails.log("new file was uploaded...")
return cbb(err, "done");
// return res.send("sent");
}
else {
// found existing user
var user = await TblUserFiles.create({
id: fileID,
customer_no: req.session.userId,
file_name: uploadedFile["filename"],
file_type: "image",
is_approved: "No",
approved_by: 0,
approved_on: today,
approved_from: ip,
uploaded_date: today,
modified_date: today
}).intercept(err => {
// Return a modified error here (or a special exit signal)
// and .create() will throw that instead
err.message = "Uh oh: " + err.message;
return err;
}).fetch();
if (user) {
sails.log("found existing files..")
return cbb(err, "done");
}
sails.log("this should not be called");
}
});
}
], (err, success) => {
if (err) sails.log(err);
return callback(err, 'done')
});
}, function (err) {
// if any of the saves produced an error, err would equal that error
if (err) {
sails.log(err);
} else {
return res.json({
message: uploadedPhotos.length + ' file(s) uploaded successfully!',
files: uploadedPhotos
});
}
});
Updated answer:
I rewrite the code.
I forgot that async.js handles promise in different way. Basically, you don't use callback(). Use return instead. If an error occurs, use throw new Error(message).
See here for more information. Read topic: Using ES2017 async functions.
async.eachSeries(uploadedPhotos, async uploadedFile => {
var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
var fileID = lastUser[0].id;
fileID += 1;
sails.log("save file id is " + file_id);
sails.log("savee file id is " + uploadedFile['filename']);
var today = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
await TblUserFiles.findOrCreate(
{ customer_no: req.session.userId, file_type: 'profile_image' },
{
id: fileID,
customer_no: req.session.userId,
file_name: uploadedFile['filename'],
file_type: 'profile_image',
is_approved: 'No',
approved_by: 0,
approved_on: today,
approved_from: ip,
uploaded_date: today,
modified_date: today
}
).exec(async (err, user, wasCreated) => {
if (err) throw new Error(err);
if (wasCreated) {
sails.log("new file was uploaded...");
return;
} else {
await TblUserFiles.create({
id: fileID,
customer_no: req.session.userId,
file_name: uploadedFile["filename"],
file_type: "image",
is_approved: "No",
approved_by: 0,
approved_on: today,
approved_from: ip,
uploaded_date: today,
modified_date: today
})
.intercept(err => {
throw new Error("Uh oh: " + err.message);
}).fetch();
if (user) {
sails.log("found existing files..");
return;
} else {
sails.log("this should not be called");
return;
}
}
});
}, err => {
// Don't call res.serverError() or res.json() inside the async loop!
if (err) {
sails.log(err);
res.serverError(err);
}
else {
res.json({
message: uploadedPhotos.length + ' file(s) uploaded successfully!',
files: uploadedPhotos
});
}
});
I think the first problem here is that the you forget to give the first task a callback function(cbb in this case).
async.waterfall([
async function(cbb) {
var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
// fileID remains undefined if i remove async-await from the function
var fileID = lastUser[0].id;
fileID += 1;
cbb(null, fileID, uploadedFile);
},
async function(file_id, uploadedFile, cbb) {
...
Secondly, you shouldn't return a callback. Callback is a function not a promise. Just use them normally.
By the way, const async = require('async'); will NOT override async keyword. Compiler can tell the difference between them. This is proved by the following script example:
const async = require('async');
let runPromise = (name, timer, success = true) => {
console.log(`${name} starts.`);
return new Promise((resolve, reject) => {
if (success) {
setTimeout(function () {
resolve(`${name} finished after ${timer / 1000} seconds(resolved).`);
}, timer);
} else {
reject(`${name} failed(rejected).`);
}
});
};
async function asyncFunction() {
let txt = await runPromise('A', 1000);
console.log(txt);
}
asyncFunction();
I am new to NodeJS and JavaScript. I am badly stuck in a problem:
I want to generate QR image of 'some text' and after generating it, I want to query my MySQL database and insert the image to database.
Problem is that QRCode.toDataURL of SOLDAIR module goes in running state and query is called before the QR image is returned from the .toDataUrl function.
Hence it results in error.
I tried everything, promises, nested promises, counters, if statements etc., but I am unable to find a solution.
My code:
router.post('/generateTicket', (req,res) => {
const query1 = `SELECT * FROM booking ORDER BY bookingID DESC LIMIT 1`;
const query2 = `INSERT INTO ticket (ticket_image,BookingID) SET ?`;
let bookingID;
let count;
let ticket_data = {};
Promise.using(mysql.getSqlConn(), conn => {
conn.query(query1).then(resultOfQuery1 => {
bookingID = resultOfQuery1[0].BookingID;
count = resultOfQuery1[0].PeopleCount;
console.log("ID = " + bookingID + " people count = "+count);
promiseToCreateQRcode().then(function (URLfromResolve) {
console.log("the url is " + URLfromResolve );
}).catch(function (fromReject) {
console.log("Rejected "+ fromReject);
}); // catch of promise to create QR
}).catch(err => {
res.json({ status: 500, message: 'Error Occured in query 1 ' + err });
}); // catch of query 1
});
});
var opts = {
errorCorrectionLevel: 'H',
type: 'image/png',
rendererOpts: {
quality: 0.3
}
};
let promiseToCreateQRcode = function () {
let QRImage;
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) throw err
console.log("\n"+url+"\n");
QRImage = url;
});
if (QRImage)
resolve(QRImage);
else
reject("error occured in url");
});
};
As u can see, the program jumps to if statement and the QR image is not generated yet, hence it goes in "reject":
Try this,
let promiseToCreateQRcode = function () {
return new Promise(function (resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err){
reject(err); // or some message
} else {
resolve(url);
}
});
});
};
This way promise will be resolved only when toDataURL returns QR image.
Have a look at How do I convert an existing callback API to promises?. You need to call resolve or reject in the asynchronous callback!
function promiseToCreateQRcode() {
return new Promise(function(resolve,reject) {
QRCode.toDataURL('text', function (err, url) {
if (err) {
reject(err);
} else {
console.log("\n"+url+"\n");
resolve(url);
}
});
});
}
Using this extra QRImage variable like you did cannot work.
I have a node based app that will look into a database for data. Because the database is fairly large with several tables, I am writing a module to help modularize the task. The problem is that I cannot get the main code to return all the data from the database lookup because I believe the program exits before it is executed. How do I get my node module working? My intention is to have the DB helper functions reside in the SomethingHelper.js module. I have the main code silly.js that looks like this:
// silly.js
var sh = require('./SomethingHelpers.js');
helper = new sh();
helper.then(function(res) {
var promise = helper.getAllForUsername('sonny');
promise.then(function(res) {
console.log('worked', res);
});
promise.catch(function(err) {
console.log('err: ', err);
});
});
helper.catch(function(err) {
console('Could not create object: ', err);
});
SomethingHelpers.js looks like this:
var mysql = require("mysql");
function SomethingHelpers() {
return new Promise(function(resolve, reject) {
this.connectionPool = mysql.createPool({
connectionLimit: 100,
host: 'server.somewhere.com',
user: "username",
password: "somepass",
database: "sillyDB",
debug: false
});
});
}
SomethingHelpers.prototype.getAllSomethingForUsername = function(username) {
var result = [];
return new Promise(function(resolve, reject) {
this.connectionPool.getConnection(function(err, connection) {
if (err) {
console.log('Error connecting to the silly database.');
return;
} else {
console.log('Connection established to the silly database. Super-Duper!');
return connection.query('SELECT something FROM somethingTable where username=\"' + username + '\"',
function(err, rows, field) {
connection.release();
if (!err) {
//console.log (rows.something);
rows.forEach(function(item) {
var allSomething = JSON.parse(item.something);
console.log(allSomething.length);
result.push(allSomething);
for (var i = 0; i < allSomething.length; i++) {
console.log(allSomething[i].handle);
}
console.log('\n\n');
});
console.log('Done');
return result;
} else {
console.log('Eeeeeeeek!');
//console.log (result);
return result;
}
});
}
});
});
} // End of getAllSomething ()
module.exports = SomethingHelpers;
I figured out the answer to my own question. Here's how I solved it. First, SomethingHelpers.js:
//SomethingHelpers.js
var mysql = require('promise-mysql');
function SomethingHelpers () {
this.pool = mysql.createPool({
connectionLimit: 100,
host: 'server.somewhere.com',
user: "username",
password: "somepass",
database: "sillyDB",
debug: false
});
}
SomethingHelpers.prototype.getAllSomethingsForThisUsername = function (username) {
let pool = this.pool;
return new Promise(function (resolve, reject) {
pool.getConnection ().then(function(connection) {
connection.query('SELECT something FROM somethingsTable where username=\"'+
username+'\"').
then (function (rows) {
resolve (getAllSomethings (rows));
}).catch (function (error) {
console.log ('Error: ', error);
});
});
});
}
function getAllSomethings (rows)
{
var result = [];
rows.forEach (function (item) {
var allSomethings = JSON.parse(item.something);
result.push (allSomethings);
});
return result;
}
module.exports = SomethingHelpers;
With the glory of Promise, the bounty from the helper module can be enjoyed thusly:
//silly.js
var hh = require ('./SomethingHelpers');
helper = new hh ();
thePromiseOfSomething = helper.getAllSomethingsForThisUsername ('sonny');
thePromiseOfSomething.then(function (rows) {
console.log (rows);
});
Thus releasing me from the tyranny of asynchronous thinking (J/K).
I want to convert the following code to use promise. It is working and output a user's attributes within the active directory.
var client = ldap.createClient({
url: ldap_url
});
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;
// It is working!!!. It outputs all user attributes.
console.log(user);
});
});
});
The following is my attempt, butit doesn't output anything.
var Promise = require('promise');
var client_bind = Promise.denodeify(client.bind);
var client_search = Promise.denodeify(client.search);
client_bind(ldap_username, ldap_password)
.then(function(err){
client_search(ldap_dn_search, opts)
.then(function(search){
var search_on = Promise.denodeify(search.on);
search_on('searchEntry')
.then(function(entry){
var user = entry.object;
// It doesn't output anything !!!
console.log(user);
});
});
});
I had the same problem.
Search emits events, so we need something that processes them and passes further along the chain.
Here is piece of code, that works for me:
var ldap = require('ldapjs');
var promise = require('bluebird');
var client = ldap.createClient({url: app.settings['ldap']['server']});
var uid;
promise.promisifyAll(client);
function searchPromise(res, notfoundtext) {
return new Promise(function(resolve, reject) {
var found = false;
res.on('searchEntry', function(entry) {
found = true;
resolve(entry);
});
res.on('error', function(e) {
reject(e.message);
});
res.on('end', function() {
if (!found) {
reject(notfoundtext);
}
});
});
}
client.searchAsync(app.settings['ldap']['baseDn'], {filter: '(mail='+credentials.email+')', scope: 'sub'})
.then(function(res) {
return searchPromise(res, 'User isn\'t exists.');
})
.then(function (entry) {
uid = entry.object.uid;
return client.bindAsync(entry.object.dn, credentials.password);
})
.then(function() {
return client.searchAsync('cn='+app.settings['ldap']['group']+',cn=groups,'+app.settings['ldap']['baseDn'], {scope: 'sub', filter: '(memberUid='+uid+')'});
})
.then(function(res) {
return searchPromise(res, 'User is not in group ' + app.settings['ldap']['group']);
})
.then(function() {
console.log('All is ok');
})
.catch(function(message) {
console.log('Error:' + message);
});
Immediately after the search I add one more step that catches the events, processes them, and passes it further along the chain. This makes the function searchPromise.
Good luck coding )
Most likely those methods do require to be called on client as a context, so you will need to bind() them before passing them to Promise.denodeify:
var client_bind = Promise.denodeify(client.bind.bind(client));
var client_search = Promise.denodeify(client.search.bind(client));
Also, a proper use of promises would look like this:
client_bind(ldap_username, ldap_password).then(function() {
return client_search(ldap_dn_search, opts);
// ^^^^^^ always return something from the callback
}).then(function(search) { // flatten your chain
return Promise.denodeify(search.on).call(search, 'searchEntry');
// ^^^^^^ an alternative to `bind`
}).then(function(entry){
var user = entry.object;
console.log(user);
}).catch(function(err) { // always catch errors!
console.error(err);
});
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);
});
}
i had the same issue here but i solved it by adding promise and resolve the response without using bluebird, this is an exemple of my code :
async getLdapUser(username: any): Promise<any> {
let myPromise = new Promise<boolean>((resolve, reject) => {
console.log('ssssssssss', username);
const adSuffix = 'OU=xxxx,OU=xxxxx,DC=xxxxxxx,DC=xxxxxx';
const password = 'xxxxxxxxxxxxx';
// Create client and bind to AD
const client = ldap.createClient({
url: 'ldap://1.1.1.1:389',
});
// promise.promisifyAll(client);
let resp = false;
// console.log(client);
client.bind('userTest', password,(err: any) => {
console.log('RESP', resp);
if (err) {
console.log('Error in new connetion ' + err);
} else {
/*if connection is success then go for any operation*/
console.log('Success');
const searchOptions: {} = {
scope: 'sub',
filter: '(sAMAccountName=' + username + ')',
attributes: ['sAMAccountName'],
};
client.search(adSuffix, searchOptions, (err: any, res: any) => {
assert.ifError(err);
res.on('searchEntry', (entry: any) => {
resp = true;
});
res.on('error', (error: any) => {
console.log('err');
reject(error.message);
});
await res.on('end', (result: any) => {
resolve(resp);
});
});
}
});
});
return myPromise;
}