From 0db53f71e06a08a53f192c0d9273cfff36c1dffc Mon Sep 17 00:00:00 2001
From: Quentin CHEVALIER <quentin.chevalier@polytechnique.edu>
Date: Wed, 21 Mar 2018 00:48:14 +0100
Subject: [PATCH] Des classes ! Tjrs + de classes !

---
 src/ldap/ldap_data.js | 927 ++++++++++++++++++++++--------------------
 1 file changed, 477 insertions(+), 450 deletions(-)

diff --git a/src/ldap/ldap_data.js b/src/ldap/ldap_data.js
index ba87a91..59523a9 100644
--- a/src/ldap/ldap_data.js
+++ b/src/ldap/ldap_data.js
@@ -32,431 +32,469 @@ var connect = JSON.parse(fs.readFileSync(connectPath, 'utf8'));
 var client = ldap.createClient({ url: config.ldap.server});
 
 //------------------------------------------------------------------------------------------------------------------------
-// Fonctions de base
+// Fonctions de base agissant sur le LDAP
 //------------------------------------------------------------------------------------------------------------------------
 
-/**
- * @summary Fonction qui sert à s'identifier sur le LDAP. Ne renvoie rien.
- * @desc Assez important en terme de sécurité, de gestion de conflit, et de droit d'accès. Méthode ldapjs 
- * (voir [`Client API`](http://ldapjs.org/client.html) méthode bind).
- * @arg {Object} user - Utilisateur de la forme suivante :
- * @arg {string} user[uid] - User identifier
- * @arg {string} user[password] - Mot de passe
-*/
-function connecterLDAP(user) { client.bind(connect.dn, connect.passwd, (err, res) => {}); } // TBM utiliser user 
+class LDAP {
+    /**
+     * @class Cette classe est la brique de base du fichier tout entier puisqu'elle contient les functions qui agisse directement sur le LDAP.
+     * @summary Constructeur vide.
+     * @author hawkspar
+    */
+    constructor() {}
+    
+    /**
+     * @summary Fonction qui sert à s'identifier sur le LDAP. Ne renvoie rien.
+     * @desc Assez important en terme de sécurité, de gestion de conflit, et de droit d'accès. Méthode ldapjs 
+     * (voir [`Client API`](http://ldapjs.org/client.html) méthode bind).
+     * @arg {Object} user - Utilisateur de la forme suivante :
+     * @arg {string} user[uid] - User identifier
+     * @arg {string} user[password] - Mot de passe
+     * @static
+    */
+    static connecter(user) { client.bind(connect.dn, connect.passwd, (err, res) => {}); } // TBM utiliser user 
 
-/**
- * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit les valeurs trouvées.
- * @desc Cette fonction appelle {@link bind} pour authentifier l'utilisateur pour authentifier l'utilisateur puis rompts la connexion.
- * Cette fonction utilise ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode search). Il faut l'appeler suivant un schéma
- * `rechercherLDAP(...).then((res) => { truc avec res });`. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma prédéfini dans `dic`
- * et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
- * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
- * @arg {string} base - DN de l'emplacement de la requête
- * @arg {string} filter ["(objectClass=*)"] - Filtre logique de la recherche (format [`RFC2254`](https://tools.ietf.org/search/rfc2254)) déjà passé au ldapEscape
- * @arg {string} filter_dic[key] - Vraie valeur pertinente de la recherche
- * @arg {string[]} attributes - Liste des attributs qui figureront dans le résultat final ; peut aussi être un seul élément
- * @return {Promise(Object[])} Résultats de la recherche ; soit une liste de valeurs d'attributs, 
- * soit une liste de dictionnaires si on veut plus d'un attribut (les clés du dictionnaire sont celles du LDAP) 
- */
-function rechercherLDAP(base, attributes, filter="(objectClass=*)") {
-    return new Promise((resolve, reject) => {
-        let vals=[];
-        // Interrogation LDAP selon configuration fournie en argument
-        client.search(base, {
-            "scope": "sub",
-            "filter": filter,
-            "attributes": attributes
-        }, function(err, res) {
-            // Gestion erreur
-            if (err) {
-                reject(err);
-            } else {
-                // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
-                res.on('searchEntry', function(entry) {
-                    // Cas un seul attribut où le résultat est une liste directement
-                    if (!Array.isArray(attributes)) { vals.push(entry.object[attributes]); }
-                    else if (attributes.length == 1) { vals.push(entry.object[attributes[0]]); }
-                    // Cas plusieurs attributs donc résultat dictionnaire
-                    else {
-                        vals.push({});
-                        attributes.forEach((attribute) => {
-                            vals.slice(-1)[0][attribute]=entry.object[attribute];
-                        });
-                    }
-                });
-                // Si la recherche est finie on se déconnecte et on renvoit la liste
-                res.on('end', function(res) { resolve(vals); });
-            }
+    /**
+     * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit les valeurs trouvées.
+     * @desc Cette fonction utilise ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode search). Il faut l'appeler suivant un schéma
+     * `rechercher(...).then((res) => { truc avec res });`. Cette fonction fait une demande au LDAP qu'elle filtre selon un schéma prédéfini dans `dic`
+     * et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
+     * @arg {string} base - DN de l'emplacement de la requête
+     * @arg {string} filter ["(objectClass=*)"] - Filtre logique de la recherche (format [`RFC2254`](https://tools.ietf.org/search/rfc2254)) déjà passé au ldapEscape
+     * @arg {string} filter_dic[key] - Vraie valeur pertinente de la recherche
+     * @arg {string[]} attributes - Liste des attributs qui figureront dans le résultat final ; peut aussi être un seul élément
+     * @return {Promise(Object[])} Résultats de la recherche ; soit une liste de valeurs d'attributs, 
+     * soit une liste de dictionnaires si on veut plus d'un attribut (les clés du dictionnaire sont celles du LDAP)
+     * @static
+     */
+    static rechercher(base, attributes, filter="(objectClass=*)") {
+        return new Promise((resolve, reject) => {
+            let vals=[];
+            // Interrogation LDAP selon configuration fournie en argument
+            client.search(base, {
+                "scope": "sub",
+                "filter": filter,
+                "attributes": attributes
+            }, function(err, res) {
+                // Gestion erreur
+                if (err) {
+                    reject(err);
+                } else {
+                    // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
+                    res.on('searchEntry', function(entry) {
+                        // Cas un seul attribut où le résultat est une liste directement
+                        if (!Array.isArray(attributes)) { vals.push(entry.object[attributes]); }
+                        else if (attributes.length == 1) { vals.push(entry.object[attributes[0]]); }
+                        // Cas plusieurs attributs donc résultat dictionnaire
+                        else {
+                            vals.push({});
+                            attributes.forEach((attribute) => {
+                                vals.slice(-1)[0][attribute]=entry.object[attribute];
+                            });
+                        }
+                    });
+                    // Si la recherche est finie on se déconnecte et on renvoit la liste
+                    res.on('end', function(res) { resolve(vals); });
+                }
+            });
         });
-    });
-}
+    }
 
-//TBT
-/**
- * @summary Fonction qui permet de modifier un élément sur le LDAP. Gestion intelligente de l'appartenance à un binet.
- * @desc Cette fonction appelle {@link bind} pour authentifier l'utilisateur pour authentifier l'utilisateur puis rompts la connexion.
- * Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs
- * (voir [`Client API`](http://ldapjs.org/client.html) méthode modify). Il faut l'appeler suivant un schéma `modifierLDAP(...).then((res) => { truc avec res });`.
- * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
- * @arg {string} name - DN de l'endroit à modifier
- * @arg {string} op - Operation à réaliser sur le LDAP. Trois opération sont possibles ; "add", qui rajoute des attributs et qui peut créer des doublons,
- * "del" qui en supprime, et "replace" qui remplace du contenu par un autre. 
- * @arg {Object} mod - Dictionnaire contenant les attributs à modifier et les nouvelles valeurs des attributs. Une nouvelle valeur vide ("") est équivalent à la suppression
- * de cet attribut.
- * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
- */
-function modifierLDAP(user, name, op, mod) {
-    return new Promise((resolve, reject) => {
-        connecterLDAP(user);
-        // Modification LDAP selon configuration en argument (pourrait prendre une liste de Changes)
-        client.modify(name, new ldap.Change({
-            operation: op,
-            modification: mod,
-        }), err => {
-            reject(err);
+    //TBT
+    /**
+     * @summary Fonction qui permet de modifier un élément sur le LDAP. Gestion intelligente de l'appartenance à un binet.
+     * @desc Cette fonction utilise une Promise pour être asynchrone ; elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs
+     * (voir [`Client API`](http://ldapjs.org/client.html) méthode modify). Il faut l'appeler suivant un schéma `LDAP.modifier(...).then((res) => { truc avec res });`.
+     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link LDAP.connecter}
+     * @arg {string} name - DN de l'endroit à modifier
+     * @arg {string} op - Operation à réaliser sur le LDAP. Trois opération sont possibles ; "add", qui rajoute des attributs et qui peut créer des doublons,
+     * "del" qui en supprime, et "replace" qui remplace du contenu par un autre. 
+     * @arg {Object} mod - Dictionnaire contenant les attributs à modifier et les nouvelles valeurs des attributs. Une nouvelle valeur vide ("") est équivalent à la suppression
+     * de cet attribut.
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon.
+     * @static
+     */
+    static modifier(name, op, mod) {
+        return new Promise((resolve, reject) => {
+            // Modification LDAP selon configuration en argument (pourrait prendre une liste de Changes)
+            client.modify(name, new ldap.Change({
+                operation: op,
+                modification: mod,
+            }), err => {
+                reject(err);
+            });
+            client.bind("", "", (err, res) => {});
+            resolve(true);
         });
-        client.bind("", "", (err, res) => {});
-        resolve(true);
-    });
-}
+    }
 
-//TBT
-/**
- * @summary Fonction qui permet de rajouter un élément sur le LDAP.
- * @desc Cette fonction appelle {@link connecterLDAP} pour authentifier l'utilisateur puis rompts la connexion. Cette fonction utilise une Promise pour être asynchrone ;
- * elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode add).
- * Il faut l'appeler suivant un schéma `modifierLDAP(...).then((res) => { truc avec res });`.
- * @arg {Object} user - Utilisateur de la forme nécessaire au {@link connecterLDAP}
- * @arg {string} dn - Adresse du parent
- * @arg {Object} vals - Dictionnaire contenant les valeurs à créer
- * @arg {string} vals[key] - Nouvelle valeur pour le champ key
- * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
- */
-function ajouterLDAP(user, dn, vals) {
-    return new Promise((resolve, reject) => {
-        connecterLDAP(user);
-        // Ajout LDAP selon la configuration en argument
-        client.add(config.key_id+"="+vals[config.key_id]+","+dn, vals, function(err) {
-            reject(err);
+    //TBT
+    /**
+     * @summary Fonction qui permet de rajouter un élément sur le LDAP.
+     * @desc Cette fonction appelle {@link LDAP.connecter} pour authentifier l'utilisateur puis rompts la connexion. Cette fonction utilise une Promise pour être asynchrone ;
+     * elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode add).
+     * Il faut l'appeler suivant un schéma `LDAP.ajouter(...).then((res) => { truc avec res });`.
+     * @arg {Object} user - Utilisateur de la forme nécessaire au {@linkoperationsLDAP. connecterLDAP}
+     * @arg {string} dn - Adresse du parent
+     * @arg {Object} vals - Dictionnaire contenant les valeurs à créer
+     * @arg {string} vals[key] - Nouvelle valeur pour le champ key
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon.
+     * @static
+     */
+    static ajouter(dn, vals) {
+        return new Promise((resolve, reject) => {
+            // Ajout LDAP selon la configuration en argument
+            client.add(config.key_id+"="+vals[config.key_id]+","+dn, vals, function(err) {
+                reject(err);
+            });
+            client.bind("", "", (err, res) => {});
+            resolve(true);
         });
-        client.bind("", "", (err, res) => {});
-        resolve(true);
-    });
-}
+    }
 
-//TBT
-/**
- * @summary Fonction qui permet de supprimer une feuille du LDAP.
- * @desc Cette fonction appelle {@link connecterLDAP} pour authentifier l'utilisateur puis rompts la connexion. Cette fonction utilise une Promise pour être asynchrone ;
- * elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode del).
- * Il faut l'appeler suivant un schéma `modifierLDAP(...).then((res) => { truc avec res });`. Cette fonction fait une demande au LDAP qu'elle filtre selon un
- * schéma prédéfini dans `dic` et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
- * Elle est différente de modify avec "del" car elle affecte directement une feuille et pas un attribut.
- * @arg {Object} user - Utilisateur de la forme nécessaire au {@link connecterLDAP}
- * @arg {string} dn - Adresse de la cible
- * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
- */
-function supprimerLDAP(user, dn) {
-    return new Promise((resolve, reject) => {
-        connecterLDAP(user);
-        // Suppression LDAP
-        client.del(dn, function(err) {
-            reject(err);
+    //TBT
+    /**
+     * @summary Fonction qui permet de supprimer une feuille du LDAP.
+     * @desc Cette fonction appelle {@link LDAP.connecter} pour authentifier l'utilisateur puis rompts la connexion. Cette fonction utilise une Promise pour être asynchrone ;
+     * elle renvoit la promesse d'une réponse puis traite la demande avec ldapjs (voir [`Client API`](http://ldapjs.org/client.html) méthode del).
+     * Il faut l'appeler suivant un schéma `LDAP.supprimer(...).then((res) => { truc avec res });`. Cette fonction fait une demande au LDAP qu'elle filtre selon un
+     * schéma prédéfini dans `dic` et à chaque résultat (event SearchEntry) le met dans une liste, et renvoit la liste à l'issue (event end).
+     * Elle est différente de modify avec "del" car elle affecte directement une feuille et pas un attribut.
+     * @arg {Object} user - Utilisateur de la forme nécessaire au {@link LDAP.connecter}
+     * @arg {string} dn - Adresse de la cible
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @static
+     */
+    static supprimer(dn) {
+        return new Promise((resolve, reject) => {
+            // Suppression LDAP
+            client.del(dn, function(err) {
+                reject(err);
+            });
+            client.bind("", "", (err, res) => {});
+            resolve(true);
         });
-        client.bind("", "", (err, res) => {});
-        resolve(true);
-    });
+    }
 }
 
 //------------------------------------------------------------------------------------------------------------------------
 // Fonctions de recherche
 //------------------------------------------------------------------------------------------------------------------------
 
-/**
- * @summary Fonction qui interroge le LDAP et retrouve les groupes (voir LDAP) qui ressemblent
- *  à l'entrée. Etape 0 vers un vrai TOL (Trombino On Line).
- * @desc Cette fonction utilise {@link rechercherLDAP} mais avec un filtre généré à la volée. 
- * Accepte des champs exacts ou incomplets mais pas approximatifs
- * et ne gère pas l'auto-complete. Cette fonction utilise aussi config.json. MEF Timeout pour
- * des recherches trop vagues. Renvoit une liste d'uid.
- * Elle utilise LDAPEscape pour éviter les injections.
- * @arg {string} input - String entré par l'utilisateur qui ressemble au nom du groupe.
- * @arg {string[]} return_attributes - Liste d'attributs à renvoyer dans le résultat final
- * @return {Promise(string[])} Liste des uid de groupes dont le nom ressemble à l'input
- */
-function trouverGroupesModulable(input, return_attributes) {
-    return new Promise((resolve, reject) => {
-        // Escape de l'input utilisateur par sécurité
-        let str=ldapEscape.filter("${txt}", { txt: input});
-
-        // Construction du filtre custom
-        let filter= "(|("+config.key_id+"="+str+")"+      // On cherche la valeur exacte
-                    "(|("+config.key_id+"=*"+str+")"+     // La valeur finale avec des trucs avant ; wildcard *
-                    "(|("+config.key_id+"=*"+str+"*)"+    // La valeur du milieu avec des trucs avant et après
-                    "("+config.key_id+"="+str+"*))))";   // La valeur du début avec des trucs après
-
-        // Appel rechercheLDAP avec filtre de l'espace 
-        rechercherLDAP(config.dn_groups, return_attributes, filter).then(res => resolve(res));
-    });
-}
+class rechercheModulable {
+    /**
+     * @class Cette classe contient des fonctions de recherche génériques trop puissantes pour être exportées tel quel.
+     * @summary Constructeur vide.
+     * @author hawkspar
+    */
+    constructor() {}
 
-/**
- * @summary Fonction qui renvoit les attributs demandés des paxs validant les critères de recherche. Première étape vers vrai TOL (Trombino On Line).
- * @desc Cette fonction utilise {@link rechercherLDAP} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets pour la plupart des champs
- * mais pas approximatifs et ne gère pas l'auto-complete. MEF Timeout pour des recherches trop vagues. Elle utilise LDAPEscape pour éviter les injections.
- * Utiliser trouverGroupesParTypes pour chaque champ relié à groups.
- * @arg {Object} data - Dictionnaire contenant les données nécessaires à la recherche. Les valeurs sont celles entrées par l'utilisateur et sont par hypothèse
- * comme des sous-parties compactes des valeurs renvoyées. Tous les champs ci-dessous peuvent être indifféremment des listes (par exempl pour chercher un membre
- * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
- * @arg {string} data[givenName] - Prénom 
- * @arg {string} data[lastName] - Nom
- * @arg {string} data[nickname] - Surnom
- * @arg {string} data[nationality] - Nationalité (non implémentée pour l'instant, pas de format spécifique)
- * @arg {string} data[promotion] - String de l'année de promo
- * @arg {string} data[phone] - String du numéro de portable
- * @arg {string} data[mail] - Adresse mail
- * @arg {string} data[ips] - Une ou des adresses ip
- * @arg {string} data[school] - Ecole d'appartenance (pour l'instant instable). Doit être exact.
- * @arg {string} data[groups] - Un ou plusieurs groupes (pas de différence entre membre simple et admin). Doit être exact.
- * @arg {string} data[studies] - PA ou autre. Doit être exact.
- * @arg {string} data[sport] - Section sportive ou autre Doit être exact.
- * @arg {string[]} return_attributes - Liste d'attributs à renvoyer dans le résultat final
- * @return {Promise(Object[])} Liste de dictionnaires de profils en cohérence avec l'input avec pour clés les attributs des profils.
- */
-function repliquerTOLModulable(data, return_attributes) {
-    return new Promise((resolve, reject) => {
-        let filter="";
-        // Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfinis dans config encore
-        for (var key in data) {
-            if ((data[key]!= undefined) & (data[key] != '')) {                    // Si il y a qque chose à chercher pour ce filtre
-                if (!Array.isArray(data[key])) { data[key]=[data[key]]; }        // Gestion d'une liste de valeurs à rechercher
-                // Iteration pour chaque valeur fournie par l'utilisateur
-                data[key].forEach(val => {
-                    // Escape de l'input utilisateur
-                    let str=ldapEscape.filter("${input}", { input: val});
-                    // Traduction en language LDAP
-                    let attribute = config.user[key];
-                    // Creation du filtre étape par étape
-                    filter="(&"+filter+ "(|("+attribute+"="+str+")"+      // On cherche la valeur exacte
-                                        "(|("+attribute+"=*"+str+")"+     // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs)
-                                        "(|("+attribute+"=*"+str+"*)"+    // La valeur du milieu avec des trucs avant et après
-                                        "("+attribute+"="+str+"*)))))";   // La valeur du début avec des trucs après
-                });
+    /**
+     * @summary Fonction qui interroge le LDAP et retrouve les groupes (voir LDAP) qui ressemblent
+     *  à l'entrée. Etape 0 vers un vrai TOL (Trombino On Line).
+     * @desc Cette fonction utilise {@link LDAP.rechercher} mais avec un filtre généré à la volée. 
+     * Accepte des champs exacts ou incomplets mais pas approximatifs
+     * et ne gère pas l'auto-complete. Cette fonction utilise aussi config.json. MEF Timeout pour
+     * des recherches trop vagues. Renvoit une liste d'uid.
+     * Elle utilise LDAPEscape pour éviter les injections.
+     * @arg {string} input - String entré par l'utilisateur qui ressemble au nom du groupe.
+     * @arg {string[]} return_attributes - Liste d'attributs à renvoyer dans le résultat final
+     * @return {Promise(string[])} Liste des uid de groupes dont le nom ressemble à l'input
+     * @static
+     */
+    static trouverGroupes(input, return_attributes) {
+        return new Promise((resolve, reject) => {
+            // Escape de l'input utilisateur par sécurité
+            let str=ldapEscape.filter("${txt}", { txt: input});
+
+            // Construction du filtre custom
+            let filter= "(|("+config.key_id+"="+str+")"+      // On cherche la valeur exacte
+                        "(|("+config.key_id+"=*"+str+")"+     // La valeur finale avec des trucs avant ; wildcard *
+                        "(|("+config.key_id+"=*"+str+"*)"+    // La valeur du milieu avec des trucs avant et après
+                        "("+config.key_id+"="+str+"*))))";   // La valeur du début avec des trucs après
+
+            // Appel rechercheLDAP avec filtre de l'espace 
+            LDAP.rechercher(config.dn_groups, return_attributes, filter).then(res => resolve(res));
+        });
+    }
+
+    /**
+     * @summary Fonction qui renvoit les attributs demandés des paxs validant les critères de recherche. Première étape vers vrai TOL (Trombino On Line).
+     * @desc Cette fonction utilise {@link LDAP.rechercher} mais avec un filtre généré à la volée. Accepte des champs exacts ou incomplets pour la plupart des champs
+     * mais pas approximatifs et ne gère pas l'auto-complete. MEF Timeout pour des recherches trop vagues. Elle utilise LDAPEscape pour éviter les injections.
+     * Utiliser trouverGroupesParTypes pour chaque champ relié à groups.
+     * @arg {Object} data - Dictionnaire contenant les données nécessaires à la recherche. Les valeurs sont celles entrées par l'utilisateur et sont par hypothèse
+     * comme des sous-parties compactes des valeurs renvoyées. Tous les champs ci-dessous peuvent être indifféremment des listes (par exempl pour chercher un membre
+     * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
+     * @arg {string} data[givenName] - Prénom 
+     * @arg {string} data[lastName] - Nom
+     * @arg {string} data[nickname] - Surnom
+     * @arg {string} data[nationality] - Nationalité (non implémentée pour l'instant, pas de format spécifique)
+     * @arg {string} data[promotion] - String de l'année de promo
+     * @arg {string} data[phone] - String du numéro de portable
+     * @arg {string} data[mail] - Adresse mail
+     * @arg {string} data[ips] - Une ou des adresses ip
+     * @arg {string} data[school] - Ecole d'appartenance (pour l'instant instable). Doit être exact.
+     * @arg {string} data[groups] - Un ou plusieurs groupes (pas de différence entre membre simple et admin). Doit être exact.
+     * @arg {string} data[studies] - PA ou autre. Doit être exact.
+     * @arg {string} data[sport] - Section sportive ou autre Doit être exact.
+     * @arg {string[]} return_attributes - Liste d'attributs à renvoyer dans le résultat final
+     * @return {Promise(Object[])} Liste de dictionnaires de profils en cohérence avec l'input avec pour clés les attributs des profils.
+     * @static
+     */
+    static trouverUtilisateurs(data, return_attributes) {
+        return new Promise((resolve, reject) => {
+            let filter="";
+            // Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfinis dans config encore
+            for (var key in data) {
+                if ((data[key]!= undefined) & (data[key] != '')) {                    // Si il y a qque chose à chercher pour ce filtre
+                    if (!Array.isArray(data[key])) { data[key]=[data[key]]; }        // Gestion d'une liste de valeurs à rechercher
+                    // Iteration pour chaque valeur fournie par l'utilisateur
+                    data[key].forEach(val => {
+                        // Escape de l'input utilisateur
+                        let str=ldapEscape.filter("${input}", { input: val});
+                        // Traduction en language LDAP
+                        let attribute = config.user[key];
+                        // Creation du filtre étape par étape
+                        filter="(&"+filter+ "(|("+attribute+"="+str+")"+      // On cherche la valeur exacte
+                                            "(|("+attribute+"=*"+str+")"+     // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs)
+                                            "(|("+attribute+"=*"+str+"*)"+    // La valeur du milieu avec des trucs avant et après
+                                            "("+attribute+"="+str+"*)))))";   // La valeur du début avec des trucs après
+                    });
+                }
             }
-        }
-        // Appel rechercheLDAP avec filtre de l'espace 
-        rechercherLDAP(config.dn_users, return_attributes, filter).then(res => resolve(res));
-    });
-}
+            // Appel rechercheLDAP avec filtre de l'espace 
+            LDAP.rechercher(config.dn_users, return_attributes, filter).then(res => resolve(res));
+        });
+    }
 
-/**
- * @summary Fonction qui retrouve les paxs validant les critères de recherche. Bien mais vite inutilisable car demande trop au LDAP et renvoie des erreurs de type size limit.
- * Préférer {@link repliquerTOLdesIds} puis {@link renseignerSurUtilisateur} au cas par cas.
- * @desc Cette fonction utilise {@link repliquerTOLModulable} avec un filtre généré à la volée. Accepte des champs incomplets mais pas approximatifs et ne gère pa
- * l'auto-complete.
- * @arg {Object} data - Dictionnaire contenant les données nécessaires à {@link repliquerTOLModulable}
- * @return {Promise(Object[])} Liste de dictionnaires de profils en cohérence avec l'input avec pour clés tous les attributs disponibles ou presque (voir config).
- */
-function repliquerTOL(data) {
-    return new Promise((resolve, reject) => {
-        repliquerTOLModulable(data, config.user.profil).then(res => resolve(res));
-    });
+    /**
+     * @summary Fonction qui retrouve les paxs validant les critères de recherche. Bien mais vite inutilisable car demande trop au LDAP et renvoie des erreurs de type size limit.
+     * Préférer {@link repliquerTOLdesIds} puis {@link renseignerSurUtilisateur} au cas par cas.
+     * @desc Cette fonction utilise {@link rechercheModulable.trouverUtilisateurs} avec un filtre généré à la volée. Accepte des champs incomplets mais pas approximatifs et ne gère pa
+     * l'auto-complete.
+     * @arg {Object} data - Dictionnaire contenant les données nécessaires à {@link repliquerTOLModulable}
+     * @return {Promise(Object[])} Liste de dictionnaires de profils en cohérence avec l'input avec pour clés tous les attributs disponibles ou presque (voir config).
+     * @static
+     */
+    static repliquerTOL(data) {
+        return new Promise((resolve, reject) => {
+            repliquerTOLModulable(data, config.user.profil).then(res => resolve(res));
+        });
+    }
 }
 
 //------------------------------------------------------------------------------------------------------------------------
 // Fonctions intermédiaires TBT
 //------------------------------------------------------------------------------------------------------------------------
 
-/**
- * @summary Cette fonction teste si un utilisateur est membre d'un groupe.
- * @desc Au passage on appelle {@link ajouterMembreGroupe} au cas où il ne soit pas membre.
- * @param {string} uid - Identifiant de l'utilisateur à tester 
- * @param {string} gid  - Identification du groupe à tester
- * @returns {Promise(boolean)} True si l'utilisateur est membre
- */
-function etreMembreGroupe(uid, gid) {
-    return new Promise((resolve, reject) => {
-        listerGroupes(uid).then(lg => {
-            listerMembres(gid).then(lm => {
-                if (lg.includes(gid) | lm.includes(uid)) {
-                        resolve(true);
-                }
+class test {
+    /**
+     * @class Cette classe contient des fonctions intermédiaires de calcul utiles mais non exportables. La plupart sont des tests contre le LDAP
+     * @summary Constructeur vide.
+     * @author hawkspar
+    */
+    constructor() {}
+
+    /**
+     * @summary Cette fonction teste si un utilisateur est membre d'un groupe.
+     * @desc Utilise les méthodes statiques listerGroupes et listerMembres de {@link utilisateurAnonyme} mais aussi ajouterMembreGroupe de {@link administrateurConnecte}
+     * @param {string} uid - Identifiant de l'utilisateur à tester 
+     * @param {string} gid  - Identification du groupe à tester
+     * @returns {Promise(boolean)} True si l'utilisateur est membre
+     * @static
+     */
+    static etreMembreGroupe(uid, gid) {
+        return new Promise((resolve, reject) => {
+            utilisateurAnonyme.listerGroupes(uid).then(lg => {
+                utilisateurAnonyme.listerMembres(gid).then(lm => {
+                    if (lg.includes(gid) | lm.includes(uid)) {
+                            superAdministrateurConnecte.ajouterMembreGroupe(uid, gid);
+                            resolve(true);
+                    }
+                });
             });
         });
-    });
-}
+    }
 
-/**
- * @summary Cette fonction teste si un utilisateur est admin d'un groupe.
- * @desc Au passage on appelle {@link ajouterAdministrateurGroupe} au cas où il ne soit pas membre.
- * @param {string} uid - Identifiant de l'utilisateur à tester 
- * @param {string} gid  - Identification du groupe à tester
- * @returns {Promise(boolean)} True si l'utilisateur est administrateur
- */
-function etreAdministrateurGroupe(uid, gid) {
-    return new Promise((resolve, reject) => {
-        listerAdministrateurs(gid).then(la => {
-            if (la.includes(uid)) {
-                resolve(true);
-            }
+    /**
+     * @summary Cette fonction teste si un utilisateur est admin d'un groupe.
+     * @desc Utilise les méthodes statiques listerAdministrateurs de {@link utilisateurAnonyme} mais aussi ajouterAdministrateurGroupe de {@link administrateurConnecte}
+     * @param {string} uid - Identifiant de l'utilisateur à tester 
+     * @param {string} gid  - Identification du groupe à tester
+     * @returns {Promise(boolean)} True si l'utilisateur est administrateur
+     * @static
+     */
+    static etreAdministrateurGroupe(uid, gid) {
+        return new Promise((resolve, reject) => {
+            utilisateurAnonyme.listerAdministrateurs(gid).then(la => {
+                if (la.includes(uid)) {
+                    superAdministrateurConnecte.ajouterAdministrateurGroupe(uid, gid);
+                    resolve(true);
+                }
+            });
         });
-    });
-}
+    }
 
-/**
- * @summary Cette fonction teste une valeur d'un attribut (typiquement un identifiant) et le fait évoluer jusqu'à ce qu'il soit unique.
- * @desc Librement adapté de Stack Overflow. Appelle {@link rechercherLDAP} pour vérifier 
- * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut
- * dans le dn fourni.
- * @param {string} valeur - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération
- * @param {string} attribut - Attribut à tester
- * @param {string} dn - *Domain Name* dans lequel l'attribut doit être unique
- * @param {function} evoluerValeur - Fonction qui prend uniquement en argument l'id courant et 
- * le nombre d'itérations et qui renvoit la prochaine valeur de l'attribut 
- * @param {int} n [0] - Nombre d'itérations (à initialiser à 0)
- * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
- */
-function assurerUnicite(valeur, attribut, dn, evoluerValeur, n=0) {
-    return new Promise((resolve, reject) => { 
-        // Recherche d'autres occurences de l'id
-        rechercherLDAP(dn, config.key_id, "("+attribut+"="+valeur+")").then(matches => {
-            // On renvoit la valeur si elle est bien unique
-            if (matches.length==0) { resolve(valeur); }
-            // Sinon, on tente de nouveau notre chance avec la valeur suivante
-            else { resolve(assurerUnicite(evoluerValeur(valeur, n+1), dn, evoluerValeur, n+1)); }
+    /**
+     * @summary Cette fonction teste une valeur d'un attribut (typiquement un identifiant) et le fait évoluer jusqu'à ce qu'il soit unique.
+     * @desc Librement adapté de Stack Overflow. Appelle {@link LDAP.rechercher} pour vérifier 
+     * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut
+     * dans le dn fourni.
+     * @param {string} valeur - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération
+     * @param {string} attribut - Attribut à tester
+     * @param {string} dn - *Domain Name* dans lequel l'attribut doit être unique
+     * @param {function} evoluerValeur - Fonction qui prend uniquement en argument l'id courant et 
+     * le nombre d'itérations et qui renvoit la prochaine valeur de l'attribut 
+     * @param {int} n [0] - Nombre d'itérations (à initialiser à 0)
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     */
+    static assurerUnicite(valeur, attribut, dn, evoluerValeur, n=0) {
+        return new Promise((resolve, reject) => { 
+            // Recherche d'autres occurences de l'id
+            LDAP.rechercher(dn, config.key_id, "("+attribut+"="+valeur+")").then(matches => {
+                // On renvoit la valeur si elle est bien unique
+                if (matches.length==0) { resolve(valeur); }
+                // Sinon, on tente de nouveau notre chance avec la valeur suivante
+                else { resolve(test.assurerUnicite(evoluerValeur(valeur, n+1), dn, evoluerValeur, n+1)); }
+            });
         });
-    });
-}
+    }
 
-/**
- * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
- * @desc Limité à un appel à {@link assurerUnicite} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
- * @param {string} givenName - Prénom
- * @param {string} lastName - Nom
- * @param {string} promotion - Année de promotion
- * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
- */
-function genererUid(givenName, lastName, promotion) {
-    // Le filtrage évite l'injection de code dans le LDAP, le normalize et lowerCase standardisent le format
-    return new Promise((resolve, reject) => {
-        assurerUnicite(ldapEscape.filter("${uid}",{uid: givenName+'.'+lastName}).toLowerCase().normalize('UFD'), config.key_id, config.dn_users, (id,n) => {
-            if (n==1) { id+='.'+ldapEscape.filter("${pr}",{pr: promotion}); }   // Si prénom.nom existe déjà, on rajoute la promo
-            else if (n==2) { id+='.'+n-1; }                                     // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1
-            else if (n>2) { id+=+n; }                                           // Ensuite on continue .23, .234, etc...
-            return id;
-        }).then(id => resolve(id));
-    });
-}
+    /**
+     * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
+     * @desc Limité à un appel à {@link test.assurerUnicite} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
+     * @param {string} givenName - Prénom
+     * @param {string} lastName - Nom
+     * @param {string} promotion - Année de promotion
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     */
+    static genererUid(givenName, lastName, promotion) {
+        // Le filtrage évite l'injection de code dans le LDAP, le normalize et lowerCase standardisent le format
+        return new Promise((resolve, reject) => {
+            test.assurerUnicite(ldapEscape.filter("${uid}",{uid: givenName+'.'+lastName}).toLowerCase().normalize('UFD'), config.key_id, config.dn_users, (id,n) => {
+                if (n==1) { id+='.'+ldapEscape.filter("${pr}",{pr: promotion}); }   // Si prénom.nom existe déjà, on rajoute la promo
+                else if (n==2) { id+='.'+n-1; }                                     // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1
+                else if (n>2) { id+=+n; }                                           // Ensuite on continue .23, .234, etc...
+                return id;
+            }).then(id => resolve(id));
+        });
+    }
 
-/**
- * @summary Cette fonction génère un gid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
- * @desc Limité à un appel à {@link assurerUnicite} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
- * @param {string} name - Nom
- * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
- */
-function genererGid(name) {
-    // Le filtrage évite l'injection de code dans le LDAP, le normalize et lowerCase standardisent le format
-    return new Promise((resolve, reject) => {
-        assurerUnicite(ldapEscape.filter("${id}",{id: name}).toLowerCase().normalize('UFD'), config.key_id, config.dn_groups, (id,n) => {
-            if (n==1) { id+='.'+n; }    // Si nom existe déjà, on essaie nom.1
-            else if (n>1) { id+=+n; }   // Ensuite on continue .12, .123, etc...
-            return id;
-        }).then(id => resolve(id));
-    });
-}
+    /**
+     * @summary Cette fonction génère un gid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
+     * @desc Limité à un appel à {@link test.assurerUnicite} avec les bons paramètres, et quelques opérations sur l'uid pour qu'il soit valide (escape, normalisation).
+     * @param {string} name - Nom
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     */
+    static genererGid(name) {
+        // Le filtrage évite l'injection de code dans le LDAP, le normalize et lowerCase standardisent le format
+        return new Promise((resolve, reject) => {
+            test.assurerUnicite(ldapEscape.filter("${id}",{id: name}).toLowerCase().normalize('UFD'), config.key_id, config.dn_groups, (id,n) => {
+                if (n==1) { id+='.'+n; }    // Si nom existe déjà, on essaie nom.1
+                else if (n>1) { id+=+n; }   // Ensuite on continue .12, .123, etc...
+                return id;
+            }).then(id => resolve(id));
+        });
+    }
 
-/**
- * @summary Cette fonction teste une valeur dummy (0) pour un identifiant numérique puis le fait évoluer aléatoirement (entre 1 et 100 000) jusqu'à ce qu'il soit unique.
- * @param {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}.
- * @param {string} attribut - Intitulé exact de l'id concerné
- * @param {string} dn - *Domain Name* dans lequel l'attribut doit être unique
- * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
- */
-function genererIdNum(attribut, dn) {
-    return new Promise((resolve,reject) => { assurerUnicite("0", attribut, dn, (id,n) => { Math.floor((Math.random() * 100000) + 1).toString(); }).then(id => resolve(id)); });
+    /**
+     * @summary Cette fonction teste une valeur dummy (0) pour un identifiant numérique puis le fait évoluer aléatoirement (entre 1 et 100 000) jusqu'à ce qu'il soit unique.
+     * @param {Object} user - Utilisateur de la forme nécessaire à {@link LDAP.connecter}.
+     * @param {string} attribut - Intitulé exact de l'id concerné
+     * @param {string} dn - *Domain Name* dans lequel l'attribut doit être unique
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     */
+    static genererIdNum(attribut, dn) {
+        return new Promise((resolve,reject) => { test.assurerUnicite("0", attribut, dn, (id,n) => { Math.floor((Math.random() * 100000) + 1).toString(); }).then(id => resolve(id)); });
+    }
 }
 
 //------------------------------------------------------------------------------------------------------------------------
 // Classes à exporter TBT
 //------------------------------------------------------------------------------------------------------------------------
 
-/**
- * @summary Cette classe est la classe de base permettant à un utilisateur non connecté de faire des petites recherches simples.
- * @desc Cette classe contient toutes les fonctions de lecture et de recherche.
- * @method listerGroupes donne liste de groupes d'un individu
- * @method listerMembres donne liste de membres d'un groupe
- * @method listerAdministrateurs donne liste d'administrateurs d'un groupe
- * @method renseignerSurUtilisateur donne toutes les infos sur une personne (non filtré !)
- * @method renseignerSurGroupe donne toutes les infos sur un groupe (non filtré !)
- * @method trouverGroupesParTypes permet de retrouver un groupe à partir d'un type et d'un nom incomplet
- * @method repliquerTOLdesIds permet de retrouver des ids à partir d'infos parcellaires
-*/
 class utilisateurAnonyme {
+    /**
+     * @class Cette classe est la classe exportable de base permettant à un utilisateur non connecté de faire des petites recherches simples.
+     * @summary Constructeur vide.
+     * @author hawkspar
+    */
+   constructor() {}
+
     //------------------------------------------------------------------------------------------------------------------------
     // Fonctions de lecture
     //------------------------------------------------------------------------------------------------------------------------
     
     /**
      * @summary Fonction qui retrouve les groupes dont un individu est membre.
-     * @desc Cette fonction utilise {@link rechercherLDAP} va directement à la feuille de l'utilisateur et n'a donc pas de filtre. Elle utilise ldapEscape pour éviter
+     * @desc Cette fonction utilise {@link LDAP.rechercher} va directement à la feuille de l'utilisateur et n'a donc pas de filtre. Elle utilise ldapEscape pour éviter
      * les injections.
      * @arg {string} uid - Identifiant de l'individu à interroger (le plus souvent prenom.nom, parfois l'année, supposé valide)
      * @return {Promise(string[])} Liste des uid de groupes (noms flat des groupes) où l'id fourni est membre
+     * @static
      */
-    listerGroupes(uid) {
+    static listerGroupes(uid) {
         return new Promise((resolve, reject) => {
-            rechercherLDAP(ldapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : uid}), config.user.groups).then(res => resolve(res[0]));
+            LDAP.rechercher(ldapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : uid}), config.user.groups).then(res => resolve(res[0]));
         });
     }
     
     /**
      * @summary Fonction qui retrouve la liste des membres d'un groupe.
-     * @desc Cette fonction utilise {@link rechercherLDAP} avec un dictionnaire prédéfini dans config.json. Elle utilise LDAPEscape pour éviter les injections.
+     * @desc Cette fonction utilise {@link LDAP.rechercher} avec un dictionnaire prédéfini dans config.json. Elle utilise LDAPEscape pour éviter les injections.
      * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule)
      * @return {Promise(String[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
+     * @static
      */
-    listerMembres(gid) {
+    static listerMembres(gid) {
         return new Promise((resolve, reject) => {
-            rechercherLDAP(ldapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : gid}), config.group.member).then(res => resolve(res[0]));
+            LDAP.rechercher(ldapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : gid}), config.group.member).then(res => resolve(res[0]));
         });
     }
     
     /**
      * @summary Fonction qui retrouve la liste des admins d'un groupe.
-     * @desc Cette fonction utilise {@link rechercherLDAP} avec un dictionnaire prédéfini dans config.json. Elle utilise LDAPEscape pour éviter les injections.
+     * @desc Cette fonction utilise {@link LDAP.rechercher} avec un dictionnaire prédéfini dans config.json. Elle utilise LDAPEscape pour éviter les injections.
      * @arg {string} gid - Identifiant du groupe à interroger (le plus souvent nom du groupe en minuscule)
      * @return {Promise(string[])} Liste des uid des membres où l'id fournie est membre (noms flat des groupes)
+     * @static
      */
-    listerAdministrateurs(gid) {
+    static listerAdministrateurs(gid) {
         return new Promise((resolve, reject) => {
-            rechercherLDAP(dapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : gid}), config.group.admin).then(res => resolve(res[0]));
+            LDAP.rechercher(dapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : gid}), config.group.admin).then(res => resolve(res[0]));
         });
     }
      
     /**
      * @summary Fonction qui renvoit toutes les infos relatives à un utilisateur particulier.
-     * @desc Cette fonction utilise {@link rechercherLDAP} avec des attributs prédéfinis. Elle utilise LDAPEscape pour éviter les injections.
+     * @desc Cette fonction utilise {@link LDAP.rechercher} avec des attributs prédéfinis. Elle utilise LDAPEscape pour éviter les injections.
      * @arg {string} uid - Identifiant de l'utilisateur
      * @return {Promise(Object[])} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet de l'utilisateur ;
      * voir `ldap_config.json`(..\..\ldap_config.json) pour les clés exactes.
+     * @static
      */
-    renseignerSurUtilisateur(uid) {
+    static renseignerSurUtilisateur(uid) {
         return new Promise((resolve, reject) => {
-            rechercherLDAP(dapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : uid}), config.user.profil).then(res => resolve(res));
+            LDAP.rechercher(dapEscape.filter(config.key_id+"=${id},"+config.dn_users, {id : uid}), config.user.profil).then(res => resolve(res));
         });
     }
      
     /**
      * @summary Fonction qui renvoit toutes les infos relatives à un groupe particulier.
-     * @desc Cette fonction utilise {@link rechercherLDAP} avec des attributs prédéfinis. Elle utilise LDAPEscape pour éviter les injections.
+     * @desc Cette fonction utilise {@link LDAP.rechercher} avec des attributs prédéfinis. Elle utilise LDAPEscape pour éviter les injections.
      * @arg {string} gid - Identifiant du groupe
      * @return {Promise(Object[])} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe ;
      * voir `ldap_config.json`(..\..\ldap_config.json) pour les clés exactes.
+     * @static
      */
-    renseignerSurGroupe(gid) {
+    static renseignerSurGroupe(gid) {
         return new Promise((resolve, reject) => {
-            rechercherLDAP(dapEscape.filter(config.key_id+"=${id},"+config.dn_groups, {id : gid}), config.group.profil).then(res => resolve(res));
+            LDAP.rechercher(dapEscape.filter(config.key_id+"=${id},"+config.dn_groups, {id : gid}), config.group.profil).then(res => resolve(res));
         });
     }
 
@@ -466,15 +504,16 @@ class utilisateurAnonyme {
 
     /**
      * @summary Fonction qui retrouve le groupe qui ressemblent à l'input et qui correspond au type fourni. Etape 0 vers un vrai TOL (Trombino On Line).
-     * @desc Cette fonction utilise {@link trouverGroupesModulable}.
+     * @desc Cette fonction utilise {@link rechercheModulable.trouverGroupes}.
      * @arg {string} input - String entré par l'utilisateur qui ressemble au nom du groupe.
      * @arg {string} type - String aux valeurs prédéfinies dans ldap_config.
-     * @return {Promise(string[])} Liste des uid de groupes dont le nom ressemble à l'input
+     * @return {Promise(string[])} Liste des uid de groupes dont le nom ressemble à l'input.
+     * @static
     */
-   trouverGroupesParTypes(input, type) {
+    static trouverGroupesParTypes(input, type) {
         return new Promise((resolve, reject) => {
             // Simple appel à la fonction précédente
-            trouverGroupesModulable(input, [config.key_id, config.group.type]).then(gList => {
+            rechercheModulable.trouverGroupes(input, [config.key_id, config.group.type]).then(gList => {
                 let gidtyList = [];
                 gList.forEach(g => {
                     // Si le groupe est du bon type on rajoute son gid
@@ -491,25 +530,23 @@ class utilisateurAnonyme {
      * @desc Cette fonction utilise {@link repliquerTOLModulable}.
      * @arg {Object} data - Dictionnaire contenant les données nécessaires à {@link repliquerTOLModulable}
      * @return {Promise(string[])} uids des profils qui "match" les critères proposés.
+     * @static
      */
-    repliquerTOLdesIds(data) {
+    static repliquerTOLdesIds(data) {
         return new Promise((resolve, reject) => {
             repliquerTOLModulable(data, config.key_id).then(res => resolve(res));
         });
     }
 }
 
-/**
- * @summary Cette classe est la classe de l'utilisateur connecté de base qui lui permet de créer un nouveau groupe ou éditer son profil.
- * @desc Cette classe contient toutes les fonctions de lecture et de recherche.
- * @constructor Un appel à {@link connecterLDAP}
- * @method creerGroupes permet à n'importe qui de créer son groupe
- * @method editerUtilisateur permet à n'importe qui de changer son profil
-*/
 class utilisateurConnecte extends utilisateurAnonyme {
-    constructor(user) {
-        connecterLDAP(user);
-    }
+    /**
+     * @class Cette classe est la classe de l'utilisateur connecté qui peut déjà créer un groupe et changer son profil.
+     * @summary Ce constructeur appelle simplement {@link LDAP.connecter}.
+     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link LDAP.connecter}.
+     * @author hawkspar
+    */
+    constructor(user) { connecterLDAP(user); }
 
     //------------------------------------------------------------------------------------------------------------------------
     // Fonction de création TBT
@@ -518,9 +555,8 @@ class utilisateurConnecte extends utilisateurAnonyme {
     /**
      * @summary Fonction qui créé un nouveau groupe dans le LDAP.
      * @desc Cette fonction fait une utilisation massive d'eval pour anonymiser son code ; c'est mal et cela suppose que beaucoup de soins ont été pris lors de
-     * l'escape de ses paramètres. Appelle {@link ajouterLDAP} et {@link modifierLDAP}, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe}
-     * pour gérer les groupes du nouvel utilisateur. Attention une manip FOIREUSE est cachée dedans. 
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * l'escape de ses paramètres. Appelle {@link LDAP.ajouter} et {@link LDAP.modifier}, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe}
+     * pour gérer les groupes du nouvel utilisateur. Attention une manip FOIREUSE est cachée dedans.
      * @arg {Object} data - Dictionnaire des informations utilisateurs (voir détail des champs dans config.json)
      * @arg {string} data[name] - Nom du groupe
      * @arg {string} data[ns] - Statut du groupe ; 'binet' ou 'free', càd ouvert à tous
@@ -528,19 +564,19 @@ class utilisateurConnecte extends utilisateurAnonyme {
      * @arg {string[]} data[admins] - Liste des admins du groupe ; supposée être une sous-liste de la précédente
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    creerGroupe(user, data) {
+    creerGroupe(data) {
         return new Promise((resolve, reject) => {
             // Calcul d'un dictionnaire d'ajout
             let vals = {};
     
             // uid de base généré à partir du nom standardisé
-            genererGid(user, data['name']).then(id => { vals[config.group['name']]=id; });
+            test.genererGid(data['name']).then(id => { vals[config.group['name']]=id; });
     
             // Ecriture de toutes les valeurs directement inscrites dans le LDAP (in pour input)
             config.group.direct_input.forEach(key_att => vals[config.group[key_att]]=data[key_att]);
     
             // Appel à la fonction de base
-            ajouterLDAP(user, config.key_id+"="+vals[config.group['name']]+","+config.dn_groups, vals).then( res => {
+            LDAP.ajouter(config.key_id+"="+vals[config.group['name']]+","+config.dn_groups, vals).then( res => {
                 // Certains champs nécessitent de petits calculs
                 let vals2={};
     
@@ -551,8 +587,8 @@ class utilisateurConnecte extends utilisateurAnonyme {
                 vals2[config.user['password']] =  '';
     
                 // Génération id aléatoire et test contre le LDAP
-                genererIdNum(user, config.groups["idNumber"], config.dn_groups).then(id => { vals2[config.group['idNumber']]=id; });
-                // FOIREUX : Hypothèse sur la structure du reste des données mais évite un assurerUnicite à deux variables
+                test.genererIdNum(config.groups["idNumber"], config.dn_groups).then(id => { vals2[config.group['idNumber']]=id; });
+                // FOIREUX : Hypothèse sur la structure du reste des données mais évite un test.assurerUnicite à deux variables
                 vals2[config.group['idNumber2']]=vals2[config.group['idNumber']];
                 
                 // Stockage machine ; dépend du prénom
@@ -569,21 +605,21 @@ class utilisateurConnecte extends utilisateurAnonyme {
                 vals2[config.group['writePerm']] = '!*';
     
                 // Inscription des valeurs calculées
-                modifierLDAP(user, config.key_id+"="+vals[config.key_id]+","+config.dn_groups, "add", vals2).then(res => {
+                LDAP.modifier(config.key_id+"="+vals[config.key_id]+","+config.dn_groups, "add", vals2).then(res => {
                     if (!res) { reject(false); }
                 });
     
                 ["posixAccount", "posixGroup", "brAccount"].forEach(cst => {
                     let vals3={};
                     vals3[config.group['class']]=cst;
-                    modifierLDAP(user, config.key_id+"="+vals[config.key_id]+","+config.dn_groups, "add", vals3).then(res => {
+                    LDAP.modifier(config.key_id+"="+vals[config.key_id]+","+config.dn_groups, "add", vals3).then(res => {
                         if (!res) { reject(false); }
                     });
                 });
     
                 // Utilisation des fonctions adaptées pour assurer la cohérence de l'ensemble
-                data['members'].forEach(uid => { ajouterMembreGroupe(user, uid, vals[config.key_att]); });
-                data['admins'].forEach(uid => { ajouterAdministrateurGroupe(user, uid, vals[config.key_att]); });
+                data['members'].forEach(uid => { this.ajouterMembreGroupe(uid, vals[config.key_att]); });
+                data['admins'].forEach(uid => { this.ajouterAdministrateurGroupe(uid, vals[config.key_att]); });
     
                 resolve(true);
             });
@@ -597,19 +633,18 @@ class utilisateurConnecte extends utilisateurAnonyme {
     
     /**
      * @summary Fonction qui édite un utilisateur existant dans le LDAP. Très similaire à {@link creerUtilisateur}
-     * @desc Appelle simplement {@link creerUtilisateur} et {@link supprimerUtilisateur}, plus {@link renseignerSurUtilisateur} pour les champs non fournis.
+     * @desc Appelle simplement {@link creerUtilisateur} et {@link supprimerUtilisateur} en godmode, plus {@link renseignerSurUtilisateur} pour les champs non fournis.
      * Ce choix a pour conséquence que l'ordre du dictionnaire de correspondance dans ldap_config est important. A modifier car donne trop de pouvoir à l'utilisateur.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
      * @arg {string} uid - Utilisateur à modifier (le plus souvent le même, mais root possible)
      * @arg {Object} data - Dictionnaire des informations utilisateurs au même format que pour {@link creerUtilisateur} avec tous les champs optionnels ;
      * MEF ces valeurs vont écraser les précédentes.
      * attention toutes les clés de cette entrée seront modifiées dans le LDAP
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    editerUtilisateur(user, uid, data) {
+    editerUtilisateur(uid, data) {
         return new Promise((resolve, reject) => {
             // Récupération des anciennes données
-            renseignerSurUtilisateur(user, uid).then(profil => {
+            super.renseignerSurUtilisateur(uid).then(profil => {
                 // Reecriture de profil avec les bons champs
                 Object.keys(profil).forEach(keyLDAP => {
                     Object.keys(config.user).forEach(keyAlias => {
@@ -618,19 +653,21 @@ class utilisateurConnecte extends utilisateurAnonyme {
                     });
                 });
                 // Régénération du champ manquant dans profil
-                listerGroupes(user, uid).then(lg => {
+                super.listerGroupes(user, uid).then(lg => {
                     profil['groupsIsAdmin']=[];
                     lg.forEach(gid =>{
-                        etreAdministrateurGroupe(user, uid, gid).then(res =>{
+                        test.etreAdministrateurGroupe(uid, gid).then(res =>{
                             if (res) { profil['groupsIsAdmin'].push(gid); }
                         }).then(res => {
                             // Surcharge des champs à modifier selon data
                             Object.keys(data).forEach(key => {
                                 profil[key]=data[key];
                             });
+                            // Passage en godmode
+                            var god = superAdministrateurConnecte({"uid":"", "password":""});
                             // Modification propre
-                            supprimerUtilisateur(user, uid).then(r => {
-                                creerUtilisateur(user, profil).then(res => { if (!res) {reject(false); }});
+                            god.supprimerUtilisateur(uid).then(r => {
+                                god.creerUtilisateur(profil).then(res => { if (!res) {reject(false); }});
                             }).then (res => { resolve(true); });
                         });
                     });
@@ -642,18 +679,15 @@ class utilisateurConnecte extends utilisateurAnonyme {
     deconnecterLDAP() { client.bind("", "", (err, res) => {}); }
 }
 
-/**
- * @summary Cette classe est la classe de l'administrateur d'un groupe qui lui permet de rajouter des membres, en supprimer, idem pour des admins,
- * ou éditer, voir supprimer le groupe.
- * @desc Cette classe contient les première fonctions de relation.
- * @method ajouterMembreGroupe permet un admin de rajouter un membre (pas de demande d'accord)
- * @method supprimerMembreGroupe inverse de la précédente
- * @method ajouterAdministrateurGroupe rajoute un administrateur
- * @method supprimerAdministrateurGroupe inverse de la précédente
- * @method editerGroupe permet de changer les informations (statut, nom...) du groupe
- * @method supprimerGroupe supprime le groupe du LDAP (beaucoup de pouvoir)
-*/
 class administrateurConnecte extends utilisateurConnecte {
+    /**
+     * @class Cette classe est la classe de l'administrateur d'un groupe qui lui permet de rajouter des membres, en supprimer, idem pour des admins,
+     * ou éditer, voir supprimer le groupe.
+     * @summary Ce constructeur appelle simplement le constructeur de sa classe mère.
+     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link LDAP.connecter}.
+     * @author hawkspar
+    */
+    constructor(user) { super(user); }
     
     //------------------------------------------------------------------------------------------------------------------------
     // Fonctions de relation TBT
@@ -661,31 +695,30 @@ class administrateurConnecte extends utilisateurConnecte {
     
     /**
      * @summary Fonction qui permet de rajouter un membre déjà créé à un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link modifierLDAP} et {@link listerGroupes}. Elle n'autorise pas les doublons et opère dans les deux dns users
+     * @desc Cette fonction fait essentiellement appel à {@link LDAP.modifier} et {@link listerGroupes}. Elle n'autorise pas les doublons et opère dans les deux dns users
      * et groups.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
      * @arg {string} uid - Identifiant du futur membre
      * @arg {string} gid - Identifiant du groupe
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    ajouterMembreGroupe(user, uid, gid) {
+    ajouterMembreGroupe(uid, gid) {
         return new Promise((resolve, reject) => {
             // Vérifie que l'utilisateur est pas déjà membre pour groupes
-            listerMembres(user,gid).then(lm => {
+            super.listerMembres(gid).then(lm => {
                 if (!lm.includes(uid)) {
                     let vals = {};
                     vals[config.groups.member] = uid;
-                    modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "add", vals).then(res => {
+                    LDAP.modifier(ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "add", vals).then(res => {
                         // Erreur si pb lors de la modification
                         if (!res) { reject(false); }
                     });
                 }
             // Vérifie que l'utilisateur est pas déjà membre pour users
-            }).then(res => listerGroupes(user,uid)).then( lg => {
+            }).then(res => super.listerGroupes(uid)).then( lg => {
                 if (!lg.includes(gid)) {
                     let vals2 = {};
                     vals2[config.users.groups] = gid;
-                    modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_users, { id: uid }), "add", vals2).then(res => {
+                    LDAP.modifier(ldapEscape(config.key_id+"=${id},"+config.dn_users, { id: uid }), "add", vals2).then(res => {
                         // Erreur si pb lors de la modification
                         if (!res) { reject(false); }
                     });
@@ -697,33 +730,32 @@ class administrateurConnecte extends utilisateurConnecte {
 
     /**
      * @summary Fonction qui permet de supprimer un membre existant d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link rechercherLDAP}, {@link modifierLDAP}, {@link listerGroupes} et {@link listerMembres}.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * @desc Cette fonction fait essentiellement appel à {@link LDAP.rechercher}, {@link operationsLDAP.LDAP.modifier}, {@link listerGroupes} et {@link listerMembres}.
      * @arg {string} uid - Identifiant de l'ex-membre
      * @arg {string} gid - Identifiant du groupe
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    supprimerMembreGroupe(user, uid, gid) {
+    supprimerMembreGroupe(uid, gid) {
         return new Promise((resolve, reject) => {
             // Vérifie que l'utilisateur est pas déjà viré pour groupes
-            listerMembres(user,gid).then(lm => {
+            super.listerMembres(gid).then(lm => {
                 if (lm.includes(uid)) {
                     // Supprime tous les utilisateurs
-                    modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "del", config.group.member).then(res => {
+                    LDAP.modifier(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "del", config.group.member).then(res => {
                         // Les rajoute un par un, sauf pour le supprimé
                         lm.forEach(id => {
-                            if (id!=uid) { ajouterMembreGroupe(user,id, gid); }
+                            if (id!=uid) { this.ajouterMembreGroupe(id, gid); }
                         });
                     });
                 }
-            }).then(res => listerGroupes(user,uid)).then(lg => {
+            }).then(res => super.listerGroupes(uid)).then(lg => {
                 // Vérifie que l'utilisateur est pas déjà viré pour users
                 if (lg.includes(gid)) {
                     // Supprime tous les groupes
-                    modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_users, { id: uid }), "del", config.group.admin).then(res => {
+                    LDAP.modifier(ldapEscape(config.key_id+"=${id},"+config.dn_users, { id: uid }), "del", config.group.admin).then(res => {
                         // Les rajoute un par un, sauf pour le supprimé
                         lg.forEach(id => {
-                            if (id!=gid) { ajouterMembreGroupe(user,uid, id); }
+                            if (id!=gid) { this.ajouterMembreGroupe(uid, id); }
                         });
                     });
                 }
@@ -734,23 +766,22 @@ class administrateurConnecte extends utilisateurConnecte {
 
     /**
      * @summary Fonction qui permet de promouvoir membre au stade d'administrateur d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link ajouterMembreGroupe} {@link modifierLDAP} et {@link listerAdministrateurs}. Elle n'autorise pas
+     * @desc Cette fonction fait essentiellement appel à {@link ajouterMembreGroupe} {@link LDAP.modifier} et {@link listerAdministrateurs}. Elle n'autorise pas
      * les doublons et opère dans les deux dns users et groups.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
      * @arg {string} uid - Identifiant du futur membre
      * @arg {string} gid - Identifiant du groupe
      * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
      */
-    ajouterAdministrateurGroupe(user, uid, gid){
+    ajouterAdministrateurGroupe(uid, gid){
         return new Promise((resolve, reject) => {
             // ajouter
-            ajouterMembreGroupe(user,uid,gid).then(res => {
-                listerAdministrateurs(user,gid).includes(uid).then(la => {
+            this.ajouterMembreGroupe(uid,gid).then(res => {
+                super.listerAdministrateurs(user,gid).includes(uid).then(la => {
                     if (!la.includes(uid)) {
                         // Finalement modification, uniquement dans groups
                         let vals = {};
                         vals[config.groups.admin] = uid;
-                        modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "add", vals).then(res => {
+                        LDAP.modifier(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "add", vals).then(res => {
                             // Gestion d'erreur
                             if (!res) { reject(false); }
                         });
@@ -763,24 +794,23 @@ class administrateurConnecte extends utilisateurConnecte {
 
     /**
      * @summary Fonction qui permet de rétrograder un membre du stade d'administrateur d'un groupe au stade d'utilisateur.
-     * @desc Cette fonction fait essentiellement appel à {@link modifierLDAP}.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * @desc Cette fonction fait essentiellement appel à {@link LDAP.modifier}.
      * @arg {string} uid - Identifiant du futur membre
      * @arg {string} gid - Identifiant du groupe
      * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
      */
-    supprimerAdministrateurGroupe(user, uid, gid) {
+    supprimerAdministrateurGroupe(uid, gid) {
         return new Promise((resolve, reject) => {
             // Peut paraître absurde mais permet de s'assurer que le membre est bien présent et que ses champs sont comme il faut
-            supprimerMembreGroupe(user, uid, gid).then( res => { ajouterMembreGroupe(user,uid,gid); });
+            this.supprimerMembreGroupe(uid, gid).then( res => { this.ajouterMembreGroupe(uid,gid); });
             // Vérifie que l'utilisateur est bien admins (comme dans supprimerMembreGroupe)
-            listerAdministrateurs(user,gid).then(la => {
+            super.listerAdministrateurs(gid).then(la => {
                 if (la.includes(uid)) {
                     // Supprime tous les administrateurs
-                    modifierLDAP(user, ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "del", config.group.admin).then(res => {
+                    LDAP.modifier(ldapEscape(config.key_id+"=${id},"+config.dn_groups, { id: gid }), "del", config.group.admin).then(res => {
                         // Les rajoute un par un, sauf pour le supprimé
                         la.forEach(id => {
-                            if (id!=uid) { ajouterAdministrateurGroupe(user, id, gid); }
+                            if (id!=uid) { this.ajouterAdministrateurGroupe(id, gid); }
                         });
                     });
                 }
@@ -794,16 +824,15 @@ class administrateurConnecte extends utilisateurConnecte {
     
     /**
      * @summary Fonction qui édite un groupe existant dans le LDAP. Très similaire à {@link creerGroupe}
-     * @desc Appelle {@link ajouterLDAP} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * @desc Appelle {@link LDAP.ajouter} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} en godmode pour gérer les groupes du nouvel utilisateur.
      * @arg {string} gid - Identifiant du groupe à modifier
      * @arg {Object} data - Dictionnaire des informations utilisateurs au même format que pour {@link creerGroupe} avec tous les champs optionnels.
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    editerGroupe(user, gid, data) {
+    editerGroupe(gid, data) {
         return new Promise((resolve, reject) => {
             // Récupération des anciennes données
-            renseignerSurGroupe(user, gid).then(profil => {
+            super.renseignerSurGroupe(gid).then(profil => {
                 // Reecriture de profil avec les bons champs
                 Object.keys(profil).forEach(keyLDAP => {
                     Object.keys(config.group).forEach(keyAlias => {
@@ -816,8 +845,8 @@ class administrateurConnecte extends utilisateurConnecte {
                     profil[key]=data[key];
                 });
                 // Modification propre
-                supprimerGroupe(user, gid).then(r => {
-                    creerGroupe(user, profil).then(res => { if (!res) { reject(false); }});
+                this.supprimerGroupe(gid).then(r => {
+                    this.creerGroupe(profil).then(res => { if (!res) { reject(false); }});
                 }).then(res => { resolve(true); });
             });
         });
@@ -830,41 +859,41 @@ class administrateurConnecte extends utilisateurConnecte {
     /**
      * @summary Fonction qui supprime un groupe du LDAP.
      * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement.
-     * Appelle {@link supprimerLDAP} bien sûr, mais aussi {@link supprimerMembreGroupe} et {@link supprimerAdministrateurGroupe} pour gérer les groupes de l'utilisateur sortant.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * Appelle {@link LDAP.supprimer} bien sûr, mais aussi {@link supprimerMembreGroupe} et {@link supprimerAdministrateurGroupe} pour gérer les groupes de l'utilisateur sortant.
      * @arg {string} gid - gid de la victime
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    supprimerGroupe(user, gid) {
+    supprimerGroupe(gid) {
         return new Promise(function(resolve, reject) {
             // Gestion des membres et administrateurs d'abord
-            renseignerSurGroupe(user, gid).then(profil => {
+            this.constructor.renseignerSurGroupe(gid).then(profil => {
                 // Ordre important
-                profil[config.group['admin']].forEach(id => { supprimerAdministrateurGroupe(user, id, gid); });
-                profil[config.group['member']].forEach(id => { supprimerMembreGroupe(user, id, gid); });
+                profil[config.group['admin']].forEach(id => { this.supprimerAdministrateurGroupe(user, id, gid); });
+                profil[config.group['member']].forEach(id => { this.supprimerMembreGroupe(user, id, gid); });
             // Elimination
             }).then(res => {
-                supprimerLDAP(user, config.key_id+"="+gid+","+config.dn_groups);
+                LDAP.supprimer(user, config.key_id+"="+gid+","+config.dn_groups);
             }).then(res => { if (res) {resolve(true); }});
         });
     }
 }
 
-/**
- * @summary Cette classe est la classe du super administrateur dieu sur terre.
- * @desc Cette classe contient les fonctions de suppression et de création utilisateurs.
- * @method creerUtilisateur créé un nouveau compte sur le LDAP
- * @method supprimerUtilisateur inverse de la précédente
-*/
 class superAdministrateurConnecte extends administrateurConnecte {
+    /**
+     * @class Cette classe est la classe du super administrateur qui créé et supprime des membres.
+     * @summary Bête appel au constructeur de la classe mère.
+     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link LDAP.connecter}.
+     * @author hawkspar
+     */
+    constructor(user) { super(user); }
+
     //------------------------------------------------------------------------------------------------------------------------
     // Fonctions de création TBT
     //------------------------------------------------------------------------------------------------------------------------
     
     /**
      * @summary Fonction qui créé un nouvel utilisateur dans le LDAP.
-     * @desc Appelle {@link ajouterLDAP} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}.
+     * @desc Appelle {@link LDAP.ajouter} bien sûr, mais aussi {@link ajouterMembreGroupe} et {@link ajouterAdministrateurGroupe} pour gérer les groupes du nouvel utilisateur.
      * @arg {Object} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis.
      * @arg {string} data[givenName] - Prénom
      * @arg {string} data[lastName] - Nom
@@ -884,28 +913,28 @@ class superAdministrateurConnecte extends administrateurConnecte {
      * @arg {string[]} data[groupsIsAdmin] [] - Liste des gid dont le pax est admin ; supposé sous-liste du précédent
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    creerUtilisateur(user, data) {
+    creerUtilisateur(data) {
         return new Promise((resolve, reject) => {
             // Calcul d'un dictionnaire d'ajout
             let vals = {};
     
             // uid de base généré à partir de nom et prénom, plus potentiellement promo et un offset
             // MEF mélange de Promise et de fonction standard
-            genererUid(user, data['givenName'],data['lastName'],data['promotion']).then(id => { vals[config.key_id]=id; } );
+            test.genererUid(data['givenName'],data['lastName'],data['promotion']).then(id => { vals[config.key_id]=id; } );
     
             // Ecriture de toutes les valeurs directement inscrites dans le LDAP (in pour input)
             // Génère une erreur si un champ n'est pas rempli
             config.user.direct_input.forEach(key_att => vals[config.user[key_att]]=data[key_att]);
     
             // Appel à la fonction de base
-            ajouterLDAP(user, config.key_id+"="+vals[config.key_id]+","+config.dn_users, vals).then( res => {
+            LDAP.ajouter(config.key_id+"="+vals[config.key_id]+","+config.dn_users, vals).then( res => {
                 // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples (d'où mul)
                 config.user.muliple_input.forEach(key_att => {
                     // On rajoute chaque valeur en entrée
                     data[key_att].forEach(val => {
                         let vals2 = {};
                         vals2[config.user[key_att]]=val;
-                        modifierLDAP(user, config.key_id+"="+vals[config.key_id]+","+config.dn_users, "add", vals2).then(res => {
+                        LDAP.modifier(config.key_id+"="+vals[config.key_id]+","+config.dn_users, "add", vals2).then(res => {
                             if (!res) { reject(false); }
                         });
                     });
@@ -923,7 +952,7 @@ class superAdministrateurConnecte extends administrateurConnecte {
                     vals3[config.user['nickname']]=data['nickname'];
                 }
                 // Génération id aléatoire unique
-                genererIdNum(user, config.user['id'], config.dn_users).then(id => { vals3[config.user['id']]=id; });
+                test.genererIdNum(config.user['id'], config.dn_users).then(id => { vals3[config.user['id']]=id; });
                 
                 // Stockage machine ; dépend du prénom
                 vals3[config.user['directory']] = '/hosting/users/' + data['givenName'][0];
@@ -945,21 +974,21 @@ class superAdministrateurConnecte extends administrateurConnecte {
                 vals3[config.user['idNum']] ='5000';
     
                 // Inscription des valeurs calculées
-                modifierLDAP(user, config.key_id+"="+vals[config.user['hruid']]+","+config.dn_users, "add", vals3).then(res => {
+                LDAP.modifier(config.key_id+"="+vals[config.user['hruid']]+","+config.dn_users, "add", vals3).then(res => {
                     if (!res) { reject(false); }
                 });
     
                 ["posixAccount", "shadowAccount", "inetOrgPerson", "brAccount"].forEach(cst => {
                     let val3={};
                     vals3[config.user['class']]=cst;
-                    modifierLDAP(user, config.key_id+"="+vals[config.user['hruid']]+","+config.dn_users, "add", vals3).then(res => {
+                    LDAP.modifier(config.key_id+"="+vals[config.user['hruid']]+","+config.dn_users, "add", vals3).then(res => {
                         if (!res) { reject(false); }
                     });
                 });
     
                 // Utilisation des fonctions adaptées pour assurer la cohérence de l'ensemble
-                data['groupsIsMember'].forEach(gid => { ajouterMembreGroupe(user, vals[config.key_id], gid); });
-                data['groupsIsAdmin'].forEach(gid => { ajouterAdministrateurGroupe(user, vals[config.key_id], gid); });
+                data['groupsIsMember'].forEach(gid => { this.ajouterMembreGroupe(vals[config.key_id], gid); });
+                data['groupsIsAdmin'].forEach(gid => { this.ajouterAdministrateurGroupe(vals[config.key_id], gid); });
     
                 resolve(true);
             });
@@ -974,28 +1003,26 @@ class superAdministrateurConnecte extends administrateurConnecte {
     /**
      * @summary Fonction qui supprime un utilisateur du LDAP.
      * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement.
-     * Appelle {@link supprimerLDAP} bien sûr, mais aussi {@link supprimerMembreGroupe} et {@link supprimerAdministrateurGroupe} pour gérer les groupes de l'utilisateur sortant.
-     * @arg {Object} user - Utilisateur de la forme nécessaire à {@link connecterLDAP}
+     * Appelle {@link LDAP.supprimer} bien sûr, mais aussi {@link supprimerMembreGroupe} et {@link supprimerAdministrateurGroupe} pour gérer les groupes de l'utilisateur sortant.
      * @arg {string} uid - uid de la victime
      * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
      */
-    supprimerUtilisateur(user, uid) {
+    supprimerUtilisateur(uid) {
         return new Promise((resolve, reject) => {
             // Gestion des groupes d'abord
-            renseignerSurUtilisateur(user, uid).then(profil => {
+            super.renseignerSurUtilisateur(uid).then(profil => {
                 profil[config.user['groups']].forEach(gid => {
-                    etreAdministrateurGroupe(user, gid).then(res => {
-                        if (la.includes(res)) { supprimerAdministrateurGroupe(user, uid, gid); }
-                    }).then(res => { supprimerMembreGroupe(user, uid, gid); });
+                    test.etreAdministrateurGroupe(gid).then(res => {
+                        if (la.includes(res)) { this.supprimerAdministrateurGroupe(uid, gid); }
+                    }).then(res => { this.supprimerMembreGroupe(uid, gid); });
                 });
             // Elimination
-            }).then(res => { supprimerLDAP(user, config.key_id+"="+uid+","+config.dn_users); });
+            }).then(res => { this.LDAP.supprimer(config.key_id+"="+uid+","+config.dn_users); });
         });
     }
 }
 
-//var u =new utilisateurAnonyme();
-//u.trouverGroupesParTypes("faerix","binet").then(res => console.log(res));
+//utilisateurAnonyme.trouverGroupesParTypes("faerix","binet").then(res => console.log(res));
 //repliquerTOL({"givenName":"almy"}).then(res => { console.log(res); });
 
 /* Partage pour le reste du monde ; même remarque synthaxe que pour l'import
-- 
GitLab