Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
5c5b2a6
Allow to get unit by unique identifier
ogiermaitre Mar 19, 2018
0c5e777
[DPR] Make getUnitById deprecated
GregLeBarbar Feb 5, 2020
6e41177
[FT.] Wildcard before keyword, not only after
GregLeBarbar Feb 5, 2020
ab84cb7
[FIX] Ensure unique email in returned array
GregLeBarbar Feb 5, 2020
762b288
[FIX] Exit mocha after tests
GregLeBarbar Feb 5, 2020
dfce549
[TST] Add some units examples
GregLeBarbar Feb 5, 2020
dc038ca
[FIX] Use a valide sciper
GregLeBarbar Feb 5, 2020
2a2abd3
[ADD] Full units mocha tests
GregLeBarbar Feb 5, 2020
d014d31
[UPD] node check update + git links
GregLeBarbar Feb 5, 2020
d943c5a
[FIX] LDAP Filter "OR" not needed
ponsfrilus Feb 5, 2020
3215773
[FIX] Search function shuld contains wildcard
ponsfrilus Feb 5, 2020
cc6b150
[TST] Cover all `user.js` function
ponsfrilus Feb 5, 2020
df9ed22
[VER] Bump to 0.7.0
ponsfrilus Feb 5, 2020
899209d
[BTF] Uniformize the 4 spaces
ponsfrilus Feb 5, 2020
fd278e6
[DOC] README updated
ponsfrilus Feb 5, 2020
f07d30c
[VER] Bump to v0.8.0
ponsfrilus Feb 5, 2020
320b81e
[FIX] node-cache update
GregLeBarbar Feb 10, 2020
e385f4f
[VER] Bump to v0.9.0
GregLeBarbar Feb 10, 2020
dcd7fb2
[ADD] flushing cache before all tests
ponsfrilus Feb 10, 2020
8e258ce
[TST] Test for searchUserByPhone added
ponsfrilus Feb 10, 2020
d10d9b5
[BTF] 4 spaces
ponsfrilus Feb 10, 2020
658438a
[RFA] Organise test in category
ponsfrilus Feb 10, 2020
f3cc2ef
[FIX] Ensure getUserByName return one result
ponsfrilus Feb 10, 2020
b799724
[REN] sciperTest → userTest
ponsfrilus Feb 10, 2020
cc68afe
[TST] More tests for getUserS
ponsfrilus Feb 10, 2020
52df440
Update README.md
ponsfrilus Feb 11, 2020
b3f458e
[ADD] flushing cache before all tests
ponsfrilus Feb 10, 2020
f8180f8
[TST] Test for searchUserByPhone added
ponsfrilus Feb 10, 2020
d39b393
[BTF] 4 spaces
ponsfrilus Feb 10, 2020
048ce59
[RFA] Organise test in category
ponsfrilus Feb 10, 2020
8808f9a
[FIX] Ensure getUserByName return one result
ponsfrilus Feb 10, 2020
9b5aed7
[REN] sciperTest → userTest
ponsfrilus Feb 10, 2020
e8a66c8
[TST] More tests for getUserS
ponsfrilus Feb 10, 2020
fd2e217
Merge branch 'test/fullcoverage' of github.com:epfl-idevelop/epfl-lda…
ponsfrilus Feb 12, 2020
6120109
[RFC] As commented here: https://github.com/stefanonepa/epfl-ldap/pul…
ponsfrilus Feb 12, 2020
4a068e6
[FT.] ByMail method + better phone handling
ponsfrilus Feb 12, 2020
0808dd3
[BTF] OCD
ponsfrilus Feb 12, 2020
9740adc
[FT.] Fix cache issues
ponsfrilus Feb 12, 2020
36b51dd
[DOC] Better comments and OCD
ponsfrilus Feb 12, 2020
e56410b
Merge pull request #4 from epfl-idevelop/test/fullcoverage
ponsfrilus Feb 12, 2020
e7d00c8
[FIX] WARNING! node-cache legacy callback support will drop in v6.x
ponsfrilus Feb 12, 2020
e73e9ac
Merge pull request #5 from epfl-si/fix/deprecatedCache
ponsfrilus Feb 12, 2020
25231c6
[RFA] epfl-idevelop → epfl-si
ponsfrilus Feb 12, 2020
67e905b
Closes the LDAP connection
GregLeBarbar Mar 3, 2020
be25ea6
Closes the LDAP connection
GregLeBarbar Mar 3, 2020
7fb521e
Merge branch 'fix-ldap-connection-close' of github.com:epfl-si/epfl-l…
GregLeBarbar Mar 3, 2020
111f1da
Merge pull request #6 from epfl-si/fix/orgRename
ponsfrilus Mar 3, 2020
2b2416d
Merge branch 'master' into fix-ldap-connection-close
ponsfrilus Mar 3, 2020
5c22053
Rename cacheQuery to _executeQuery + hoist to top level
GregLeBarbar Mar 3, 2020
edc8f6d
Refactor to extract uniqueness logic
GregLeBarbar Mar 3, 2020
7b5668c
convert next() to Promise
GregLeBarbar Mar 3, 2020
21fc9b2
[refactor] extract ldapjs-promise.js
GregLeBarbar Mar 3, 2020
8f37efc
tiny improvements
GregLeBarbar Mar 4, 2020
a1c2a20
Merge branch 'fix-ldap-connection-close' of github.com:epfl-si/epfl-l…
ponsfrilus Mar 4, 2020
bc794bb
[refactor] Export the ConnectionPool class
ponsfrilus Mar 4, 2020
6a6cd2b
[refactor] uses the connectionPool in client.js
ponsfrilus Mar 4, 2020
42c9cca
[remove] dead code
ponsfrilus Mar 4, 2020
948d8ba
[move] test.js as connectionPool sample, tests scripts updated
ponsfrilus Mar 4, 2020
7d9678d
[doc] example with custom search base
ponsfrilus Mar 4, 2020
719cd63
[feature] Options for poolSize and searchBase
ponsfrilus Mar 4, 2020
6801f92
Merge pull request #7 from epfl-si/fix-ldap-connection-close
GregLeBarbar Mar 4, 2020
1604ffc
1.0.0
GregLeBarbar Mar 4, 2020
28d87e1
[release] convert package-lock.json to npm-shrinkwrap.json
GregLeBarbar Mar 4, 2020
e0dfa5d
[fix] Tests data (#8)
williambelle Feb 17, 2025
c8df1d7
[fix] Revert npm-shrinkwrap.json to package-lock.json (#9)
williambelle Feb 17, 2025
d73a83b
[chore] bump version to 1.0.1
williambelle Feb 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# epfl-ldap

Simple wrapper to query the epfl ldap
Simple wrapper to query the EPFL LDAP.

## Usage
```javascript
Expand Down Expand Up @@ -43,17 +43,23 @@ customLdapContext.options.modelsMapper = customModelsMapper;
customLdapContext.users.getUserBySciper(169419, function (err, data) {
console.log(JSON.stringify(data, null, 2));
});
```

## Notes

⚠ Carefull with the results formats (Object or Array)
/*
* Custom Options
*/
var publicLdapContext = require('epfl-ldap')({
searchBase:'ou=si-idev,ou=si,o=epfl,c=ch',
poolSize: 4
});
publicLdapContext.users.getUserBySciper(169419, function(err, data) {
console.log(JSON.stringify(data, null, 2));
});
```

⚠ this library *"try"* to use ES2015 (or ES6) capabilities, don't use it with nodejs under 4.x?

## Notes

## TODO
⚠ Carefull with the results formats (Object or Array)

- [ ] add tests
- [ ] add samples
- [ ] implement query validation with the package `epfl-exceptions`
⚠ this library *"try"* to use ES2015 (or ES6) capabilities, don't use it with nodejs under 5.x?
132 changes: 64 additions & 68 deletions client.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,78 @@
'use strict';

module.exports = function ldapClient(context) {

let ldap = require('ldapjs');
let client = ldap.createClient({
url: 'ldap://ldap.epfl.ch',
timeLimit: 1,
sizeLimit: 10
});

function cacheQuery(ldapQuery, objectFactory, modelMapper, isResultUniq, next) {
let opts = {
filter: ldapQuery,
scope: 'sub'
};

client.search(context.options.searchBase, opts, function (err, ldapRes) {
let groupedObject = {};
const _executeQueryPromise = require('./ldapjs-promise');
const ConnectionPool = require('./connection-pool.js');

ldapRes.on('searchEntry', function (entry) {
if (typeof entry.json != 'undefined') {
let objectIdentifier = entry.object.uniqueIdentifier;
if (groupedObject[objectIdentifier] === undefined) {
groupedObject[objectIdentifier] = Array();
}
groupedObject[objectIdentifier].push(entry.object);
} else {
next(null, groupedObject);
function _executeQueryInPool(pool, searchBase, ldapQuery, next) {
pool.add(function(client) {
_executeQueryPromise(client, searchBase, ldapQuery)
.then(
(data) => {
next(null, data);
}
});
ldapRes.on('searchReference', function (referral) {
//console.log('referral: ' + referral.uris.join());
});
ldapRes.on('error', function (err) {
console.error('error: ' + err.message);
next(err, null);
});
ldapRes.on('timeout', function (err) {
console.error('error: ' + err.message);
next(err, null);
});
ldapRes.on('end', function () {
let objectsGroup = Array();

for (let userEntry in groupedObject) {
if (groupedObject.hasOwnProperty(userEntry)) {
if (isResultUniq) {
objectsGroup = modelMapper(objectFactory(groupedObject[userEntry]));
} else {
objectsGroup.push(modelMapper(objectFactory(groupedObject[userEntry])));
}
}
)
.catch(
(err) => {
next(err, null);
}
next(null, objectsGroup);
});
)
});
}
}

function createPool(clientFactory, opts) {
const pool = new ConnectionPool(
opts.poolSize,
clientFactory,
(client) => client.unbind()
);
return pool;
}

client.executeQuery = function(ldapQuery, objectFactory, modelMapper, isResultUniq, next) {
context.memoryCache.get(ldapQuery, function (err, data) {
if (!err) {
if (data == undefined) {
cacheQuery(ldapQuery, objectFactory, modelMapper, isResultUniq, function(err, data) {
context.memoryCache.set(ldapQuery, data, function (err, success) {
if (!err && success) {
next(null, data);
module.exports = function ldapClient(context) {

let ldap = require('ldapjs');
let pool = createPool(() => ldap.createClient({
url: 'ldap://ldap.epfl.ch',
timeLimit: 1,
sizeLimit: 10
}),
{ poolSize : context.poolSize }
);

const client = {
executeQuery: function(ldapQuery, objectFactory, modelMapper, isResultUniq, next) {
let objectsGroup = context.memoryCache.get(ldapQuery+isResultUniq)
if (objectsGroup == undefined) {
let searchBase = context.options.searchBase;
let opts = {
filter: ldapQuery,
scope: 'sub'
};
_executeQueryInPool(pool, searchBase, opts, function(err, data) {

let objectsGroup = Array();

for (let userEntry in data) {
if (data.hasOwnProperty(userEntry)) {
if (isResultUniq) {
objectsGroup = modelMapper(objectFactory(data[userEntry]));
} else {
next({ Error: "aararrggghhh!" }, null);
objectsGroup.push(modelMapper(objectFactory(data[userEntry])));
}
});
});
} else {
next(null, data);
}
}
}

let success = context.memoryCache.set(ldapQuery+isResultUniq, objectsGroup);
if (success) {
next(null, objectsGroup);
} else {
next({ Error: "Error setting cache" }, null);
}
});
} else {
next({ Error: "aararrggghhh!" }, null);
next(null, objectsGroup);
}
});
}
};

return client;
Expand Down
60 changes: 60 additions & 0 deletions connection-pool.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const debug = require('debug')('connection-pool');
const PSemaphore = require('promise-semaphore');

module.exports = class ConnectionPool {

constructor(n, create, destroy) {
this.roomsLength = n;
this.pSemaphore = new PSemaphore({rooms: this.roomsLength});
this.create = create;
this.destroy = destroy;
this.rooms = [
//{ free: false, client: null}
];
}

add(f) {
return this.pSemaphore.add(async () => {
debug("GET");
let client = this._get();
try {
return await f(client);
} finally {
debug("PUT");
this._put(client);
}
});
}

_get() {
for(let i=0; i < this.roomsLength; i++) {
if (!this.rooms[i]) {
this.rooms[i] = {
free: true,
client: this.create()
}
}
// Room is furnished
if (this.rooms[i].free) {
this.rooms[i].free = false;
return this.rooms[i].client;
} else {
// continue
}
}
}

_put(client) {
this.rooms.forEach(room => {
if (room.client === client) {
room.free = true;
}
})
}

close() {
this.rooms.forEach(room => {
this.destroy(room.client);
})
}
}
20 changes: 14 additions & 6 deletions context.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
'use strict';
let NodeCache = require("node-cache");
module.exports = function ldapContext(options) {
let NodeCache = require("node-cache");
let context = {};
// Define the pool size
if (options == undefined || options.poolSize == undefined ) {
context.poolSize = 3;
} else {
context.poolSize = options.poolSize;
}
context.options = require('./options')(options);
context.client = require('./client')(context);
context.options = require('./options')();
context.users = require('./repositories/users')(context);
context.units = require('./repositories/units')(context);
context.viewModelsMappers = require('./viewModels/mappers')();

if (options == undefined || options.memoryCache == undefined ) {
context.memoryCache = new NodeCache({ stdTTL: 14400 }); // 4 hour of cache
} else {
context.memoryCache = new NodeCache(options.memoryCache);
if (context.memoryCache == undefined) {
if (options == undefined || options.memoryCache == undefined ) {
context.memoryCache = new NodeCache({ stdTTL: 14400 }); // 4 hour of cache
} else {
context.memoryCache = new NodeCache(options.memoryCache);
}
}
return context;
};
32 changes: 32 additions & 0 deletions ldapjs-promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = function _executeQueryPromise(client, searchBase, opts) {
return new Promise((resolve, reject) => {
client.search(searchBase, opts, function (err, ldapRes) {
let groupedObject = {};
ldapRes.on('searchEntry', function (entry) {
if (typeof entry.json != 'undefined') {
let objectIdentifier = entry.object.uniqueIdentifier;
if (groupedObject[objectIdentifier] === undefined) {
groupedObject[objectIdentifier] = Array();
}
groupedObject[objectIdentifier].push(entry.object);
} else {
resolve(groupedObject);
}
});
ldapRes.on('searchReference', function (referral) {
//console.log('referral: ' + referral.uris.join());
});
ldapRes.on('error', function (err) {
console.error('error: ' + err.message);
reject(err);
});
ldapRes.on('timeout', function (err) {
console.error('error: ' + err.message);
reject(err);
});
ldapRes.on('end', function () {
resolve(groupedObject);
});
});
});
}
14 changes: 6 additions & 8 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ module.exports = function User(ldapUserArray) {
userModel.accreds = Array();
userModel.memberOf = Array();
userModel.photoUrl = 'http://people.epfl.ch/cgi-bin/people/getPhoto?id=' + userModel.sciper;

if (ldapUserArray[0].memberOf !== undefined) {

// Note: if only one group, typeof string
// if groups, typeof object.
// Username banla have only one group
Expand All @@ -25,13 +24,12 @@ module.exports = function User(ldapUserArray) {
userModel.memberOf = ldapUserArray[0].memberOf;
}
}

ldapUserArray.map(function (userEntry) {
if (userEntry.mail != undefined) {
if (userEntry.mail instanceof Array) {
userEntry.mail.map(function(mail) {
userModel.emails.push(mail);
});
// This remove duplicated entries and allow more than one email
userModel.emails = [...new Set(userEntry.mail)];
} else {
userModel.emails.push(userEntry.mail);
}
Expand All @@ -49,8 +47,8 @@ module.exports = function User(ldapUserArray) {
}
);
});
//All ldap properties

// All ldap properties
userModel.optionalProperties = ldapUserArray;

return userModel;
Expand Down
9 changes: 7 additions & 2 deletions options.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
'use strict';
module.exports = function () {
module.exports = function (options) {
let ldapOptions = {};
ldapOptions.searchBase = 'c=ch';
// Define the searchBase
if (options == undefined || options.searchBase == undefined ) {
ldapOptions.searchBase = 'c=ch';
} else {
ldapOptions.searchBase = options.searchBase;
}
ldapOptions.modelsMapper = require('./viewModels/public/modelsMapper')();
return ldapOptions;
};
Loading