undefined is not a function while writing a promise function in Nodejs - javascript

I am trying to write a function of mine using Bluebird promise Library.
I promisified the ldap-js the createClient function of ldap-js by:
var Promise= require('bluebird'); //done at the beginning
var createClientAsync = Promise.promisify(require('ldapjs').createClient);
getUser:function(user) {
var memberRoles = [];
var searchFilter = '(&(member='+user.dn+'))';
var opts = {
filter: searchFilter,
scope: 'sub',
attributes: ['dn']
};
createClientAsync({
url: 'ldap://x.x.x.x:3889'
})
.then(function(client){
return client.search('o=pic', opts);
})
.then(function(res) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
for (var role in roles) {
var mapping = roles[role];
if (mapping.group === entry.object.dn) {
memberRoles.push(role);
}
}
});
})
.then(function() {
return memberRoles;
});
}
I get an error at createClientAsync undefined is not a function.

After a brief reading of the ldapjs documentation, I can suggest the following code
getUser:function(user) {
var searchFilter = '(&(member='+user.dn+'))';
var opts = {
filter: searchFilter,
scope: 'sub',
attributes: ['dn']
};
return createClientAsync({
url: 'ldap://x.x.x.x:3889'
})
.then(function(client){
return client.search('o=pic', opts);
})
.then(function(res) {
var memberRoles = [];
return new Promise(function(resolve, reject) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
for (var role in roles) {
var mapping = roles[role];
if (mapping.group === entry.object.dn) {
memberRoles.push(role);
}
}
});
res.on('end', function() {
resolve(memberRoles);
});
});
});
}
note the "new Promise" and res.on('end' to resolve the promise once the "search" has completed
as I said, brief reading of documentation, so this may be completely invalid :p

Related

Service call in for loop angular js $q, promise

Service call in for loop angular js $q, promise
var FULLWEEKDAYS = [MONDAY, TUESDAY ... SATURDAY]
for (var i=0; i< FULLWEEKDAYS.length; i++) {
var reqParams = {
weekday: FULLWEEKDAYS[i],
teacherId : 97
}
TimetableService.getTeachersOccupancy(reqParams, function (data)
{
if (data) {
$scope.weeklyData.push(data);
}
}, function (err) {
//message.error('Timetable', err.data);
});
}
Serivice call is
function getTeachersOccupancy(data, successFunction, errorFunction) {
var params = $.param(data);
AjaxHandlerFactory.AjaxGet(BASETIMETABLEPATH + 'occupancy?' +
params, {}, function (response) {
successFunction(response.data);
}, function (error) {
errorFunction(error);
});
}
Question:
$scope.weeklyData.length = 0 outside for loop. Why and how to handle this in promises?
Serivce call
function getTeachersOccupancy(data, successFunction, errorFunction) {
// /SchoolAdminWS/services/schools/{schoolCd}/timeTable/occupancy?classroomId={classroomId}&date={YYYY-MM-DD}
var params = $.param(data);
***var deferred = $q.defer();***
AjaxHandlerFactory.AjaxGet(BASETIMETABLEPATH + 'occupancy?' + params, {}, function (response) {
successFunction(response.data);
***deferred.resolve(response.data);***
}, function (error) {
errorFunction(error);
***deferred.reject(error);***
});
***return deferred.promise;***
}
While calling above service, create a variable promise=[]; push all repsonses from service call, and resolve them.
var promises = [];
for (var i=0; i< FULLWEEKDAYS.length; i++) {
var reqParams = {
weekday: FULLWEEKDAYS[i],
teacherId : vm.employeeProfileId
}
var promise = TimetableService.getTeachersOccupancy(reqParams, function () {}, function () {});
promises.push(promise);
}
Now resolve using $q.all()
$q.all(promises).then(function(value) {
vm.weeklyData = value;
console.log(vm.weeklyData);
setTeacherOccupancyData(value);
vm.isSearch = true;
}, function (reason) {
console.log("Promise Rejected:" + reason);
});

Second promise is not working properly

I have the following promise that works perfectly:
self.getAll = function (callback) {
var users= [];
var promises = [];
$.ajax({
url: "/API/Users",
type: "GET",
success: function (results) {
var mappedContacts = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts/" + item.id,
type: "GET"
}).then(function (contacts) {
users.push(new User(item, contacts));
}));
});
$.when.apply($, promises).then(function () {
callback(users);
});
}
});
}
I'm trying to add a second AJAX request but it's not working properly:
self.getAll = function (callback) {
var users= [];
var promises = [];
$.ajax({
url: "/API/Users",
type: "GET",
success: function (results) {
var mappedContacts = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts/" + item.id,
type: "GET"
}).then(function (contacts) {
users.push(new User(item, contacts));
}));
});
var mappedContacts2 = $.map(results, function (item) {
promises.push($.ajax({
url: "/API/Users/contacts2/" + item.id,
type: "GET"
}).then(function (contacts2) {
users.push(new User(item, "",contacts2));
}));
});
$.when.apply($, promises).then(function () {
callback(users);
});
}
});
}
contacts2 is always empty, what am I doing wrong?
This is the User object:
var User= function (data, contacts, contacts2) {
this.id = ko.observable(data.id);
this.name = ko.observable(data.name);
this.contacts = ko.observableArray(contacts);
this.contacts2 = ko.observableArray(contacts2 );
}
Since you need both sets of contacts for each user to pass to new User() use one map() that returns a $.when() for both contacts requests. Create the user in then() of that $.when()
Something like:
self.getAll = function(callback) {
var users = [];
// return this promise ..... see notes below
return $.getJSON("/API/Users").then(results) {
// map array of promises to pass to final $.when
var promises = $.map(results, function(item) {
var req1 = $.getJSON("/API/Users/contacts/" + item.id);
var req2 = $.getJSON("/API/Users/contacts2/" + item.id);
// return this promise to mapped array
return $.when(req1, req2).then(function(contacts1, contacts2) {
// create user now that we have both sets of contacts
users.push(new User(item, contacts1, contacts2));
});
})
// should return this promise .... see notes below
return $.when.apply($, promises).then(function() {
callback(users);
// return `users` ...see notes below
});
})
}
Using a callback is an outdated approach when you could just return the promise chain shown in comments above and do :
self.getAll().then(function(users) {
// do something with users
})

Implemented Bluebird nested loops promise in Node JS

I'm using bluebird in NodeJS. I want to do a nested loop. Something like this:
var Promise = require('bluebird');
funcs.getLatestVideos = function(job, done) {
return Promise.try(function() {
return ProcessRules.getLatestVideos();
})
.then(function(object) {
return ({
'series': ProcessRules.getSeriesRules(),
'videos': object.videos
});
})
.then(function(inputs) {
return Promise.map(inputs.videos, function(video) {
return Promise.map(inputs.series, function(series) {
return Promise.map(series.rules, function(rule) {
return ProcessRules.processRules(video, rule);
});
});
})
})
.then(function(result) {
W.debug("done");
console.log(JSON.stringify(result));
done();
})
.catch(function(err) {
done(err);
W.error("Error occurred ", err.message, err.stack);
});
}
ProcessRules
var Promise = require('bluebird');
var rp = require('request-promise');
var W = require('winston');
var RuleEngine = require('node-rules');
var _ = require('lodash');
funcs.getSeriesRules = function() {
return new Promise(function(resolve, reject) {
var options = {
method: "GET",
uri: API_URL,
// body: status,
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(function(result) {
resolve(result)
})
.catch(function(err) {
reject(err)
});
});
};
funcs.processRules = function(fact, rule) {
return new Promise(function(resolve, reject) {
var rules = [];
var value = new RegExp(rule.value, 'i');
switch (rule.type) {
case 'title':
rules = [{
"condition": function(R) {
// console.log(this.title.match(value));
R.when(this.title.match(value) > -1);
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
case 'desc':
rules = [{
"condition": function(R) {
//console.log(this.desc.match(value));
R.when(this.desc.match(value) > -1);
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
case 'tag':
rules = [{
"condition": function(R) {
// console.log(this.tag.match(value));
R.when(!_.some(this.tags, { 'text': rule.value}))
},
"consequence": function(R) {
this.result = false;
this.video = R;
R.stop();
}
}];
break;
default:
break
};
//initialize the rule engine
const R = new RuleEngine(rules);
//Now pass the fact on to the rule engine for results
R.execute(fact, function(result) {
//console.log(result);
if (result.result) {
resolve(result._id)
}else{
resolve({})
}
});
});
};
It returns me following output
[[[{},{},"58e9d6816961c30367b5154c"],[{}],[],[],[]],[[{},{},"58e9d6816961c30367b5154d"],[{}],[],[],[]]]
But I am expecting with following output:
[58e9d6816961c30367b5154c,58e9d6816961c30367b5154d]
I see some similar question but not getting exact ideas from them.
In getLatestVideos function not able to get done result ,Please help me to resolve this issue.
Please help me to implement nested each loop with bluebird promise.
After long search with multiple questions and answers , I got the answer by Flattening a Promise map.
I don't know exactly its right way but its working for me.
.then(function(inputs) {
return Promise.map(inputs.videos, function(video) {
return Promise.map(inputs.series, function(series) {
return Promise.map(series.rules, function(rule) {
return ProcessRules.processRules(video, rule);
}).reduce(function(prev, cur) {
return cur ? prev.concat(cur) : [];
}, [])
}).reduce(function(prev, cur) {
return prev.concat(cur);
}, [])
}).reduce(function(prev, cur) {
return prev.concat(cur);
}, [])
})
It returns me [58e9d6816961c30367b5154c,58e9d6816961c30367b5154d].
Thanks Everyone.

keystone.js nested promise -> foreach -> list find scope issue

I am writing an service, where I retrieve a list of items from a another service, then iterate over result performing keystone.list operation(s).
I am loosing the return status in the find/exec operation. I have tried promises, async, etc.
If someone could point out the correct way to implement this, I would appreciate it.
general implementation:
exports = module.exports = function (req, res) {
var rtn = {
added: 0,
count: 0
}
service(params)
.then(function(svcResult) {
svcResult.forEach(function(item) {
rtn.count++; // <-- correctly seen in apiresponse
Artifact.model.find()
.where({ artifactId: item.id})
.exec(function(err, result) {
if (result.length == 0) {
result = new Artifact.model({
... populate from item ....
});
result.save();
rtn.added++; // <-- not seen in api response
});
});
res.apiResponse(rtn);
});
}
for starters, exec is an async call, which you are ignoring in your res.apiResponse and thus count is incremented and not added, to make life easy, I am moving the exec call outside and wrapping it with promise:
function pExec(id){
return new Promise(function(resolve, reject){
Artifact.model.find()
.where({ artifactId: id})
.exec(function(err, result){
console.log('result: ', result); // there is a possibility that this is not empty array, which seems to be the only case when you increment added value
err? reject(err): resolve(result);
});
});
}
exports = module.exports = function(req, res){ // I think it is 'exports' not 'exposts'
service(params)
.then(function(svcResult) {
var promises = svcResult.map(function(item){
rtn.count++;
return pExec(item.id).then(function(result){
if (result.length == 0) {
result = new Artifact.model({
//... populate from item ....
});
result.save(); // again this might be an async call whose response you might need before incrementing added...
rtn.added++; // <-- not seen in api response
};
});
});
Promise.all(promises).then(function(){
res.apiResponse(rtn);
});
});
}
Thanks... Here is what I have come up with so far....
function getArtifact(id) {
return new Promise(function (resolve, reject) {
Artifact.model.findOne()
.where({artifactId: id})
.exec(function (err, artifact) {
err ? resolve(null) : resolve(artifact);
});
});
}
function createArtifact(item) {
return new Promise(function (resolve, reject) {
var artifact = new Artifact.model({
// ... populate from item ....
});
artifact.save(function (err, artifact) {
err ? resolve(null) : resolve(artifact);
});
});
}
exports = module.exports = function (req, res) {
var rtn = {
success: false,
count: 0,
section: '',
globalLibrary: {
Added: 0,
Matched: 0
},
messages: [],
};
if (!req.user || !req.user._id) {
rtn.messages.push("Requires Authentication");
return res.apiResponse(rtn);
}
if (!req.params.section) {
rtn.messages.push("Invalid parameters");
return res.apiResponse(rtn);
}
var userId = req.user._id;
var section = req.params.section;
rtn.section = section;
service(section)
.then(function (svcResult) {
if (svcResult.length == 0 || svcResult.items.length == 0) {
rtn.messages.push("Retrieved empty collection");
return;
}
rtn.messages.push("Retrieved collection");
var artifacts = svcResult.items(function (item) {
rtn.count++;
return getArtifact(item.objectid)
.then(function (artifact) {
if (!artifact || artifact.length == 0) {
rtn.messages.push("Global Library Adding: " + item.name['$t']);
rtn.globalLibrary.Added++;
artifact = createArtifact(item);
} else {
rtn.globalLibrary.Matched++;
}
return artifact;
})
});
Promise.all(artifacts)
.then(function () {
rtn.success = true;
res.apiResponse(rtn);
});
});
}

Use ldapjs with promise

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;
}

Categories