diff --git a/package.json b/package.json
index b7b45d8c5fb7577144f0386df6c8075cc434e03f..0d5a191c848be3fca2494d7bafa76bb7900d7909 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
     "eslint": "eslint --ext .js src/ db/",
     "tslint": "tslint --project tsconfig.json",
     "tsfix": "tslint --project tsconfig.json --fix",
+    "tsc": "tsc --project tsconfig.json",
     "test": "mocha --exit"
   },
   "repository": {
diff --git a/src/ldap/export/group.js b/src/ldap/export/group.js
deleted file mode 100644
index fc2be13bbc7ec617f9942c1dade45d76e62f611a..0000000000000000000000000000000000000000
--- a/src/ldap/export/group.js
+++ /dev/null
@@ -1,453 +0,0 @@
-"use strict";
-/**
- * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
- * @author hawkspar
- */
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __generator = (this && this.__generator) || function (thisArg, body) {
-    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
-    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
-    function verb(n) { return function (v) { return step([n, v]); }; }
-    function step(op) {
-        if (f) throw new TypeError("Generator is already executing.");
-        while (_) try {
-            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
-            if (y = 0, t) op = [0, t.value];
-            switch (op[0]) {
-                case 0: case 1: t = op; break;
-                case 4: _.label++; return { value: op[1], done: false };
-                case 5: _.label++; y = op[1]; op = [0]; continue;
-                case 7: op = _.ops.pop(); _.trys.pop(); continue;
-                default:
-                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
-                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
-                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
-                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
-                    if (t[2]) _.ops.pop();
-                    _.trys.pop(); continue;
-            }
-            op = body.call(thisArg, _);
-        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
-        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
-    }
-};
-exports.__esModule = true;
-var config_1 = require("../internal/config");
-var basics_1 = require("../internal/basics");
-var tools_1 = require("../internal/tools");
-//------------------------------------------------------------------------------------------------------------------------
-// Classes à exporter TBT
-//------------------------------------------------------------------------------------------------------------------------
-var Group = /** @class */ (function () {
-    /**
-     * @memberof LDAP
-     * @class Group
-     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les groupes.
-     * @summary Constructeur vide.
-     */
-    function Group() {
-    }
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui renvoit toutes les infos relatives à un groupe particulier.
-     * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link groupData}. Elle rajoute les individus
-     * @arg {string} gid - Identifiant du groupe
-     * @return {Promise(groupData)} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe au format {@link groupData}.
-     * @static
-     * @async
-     */
-    Group.peek = function (gid) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, tools_1.Tools.peek("group", gid, config_1.groupData)];
-                }
-                catch (err) {
-                    throw "Erreur lors d'une recherche d'informations sur un groupe.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @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) pour les groupes.
-     * @desc Cette fonction utilise {@link Tools.search}.
-     * @arg {groupData} input - String entré par l'utilisateur qui ressemble au nom du groupe.
-     * @return {Promise(string[])} Liste des gid dont le nom ressemble à l'input.
-     * @static
-     * @async
-    */
-    Group.search = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, tools_1.Tools.search("group", data)];
-                }
-                catch (err) {
-                    throw "Erreur lors de la recherche approximative d'un groupe.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de rajouter un administrateur à un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Le nouvel administrateur ne devient pas membre ou porte-parole du groupe pour autant !
-     * @arg {string} uid - Identifiant du membre futur admin
-     * @arg {string} gid - Identifiant du groupe
-     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.addAdmin = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            switch (_a.label) {
-                case 0: return [4 /*yield*/, tools_1.Tools.add(uid, gid, "admins")];
-                case 1: return [2 /*return*/, _a.sent()];
-            }
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de supprimer un administrateur.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}.
-     * Elle ne remonte pas les échelons, car cela permettrait à un admin d'un petit groupe de supprimer un admin d'un grand.
-     * @arg {string} uid - Identifiant de l'admin à dégrader, supposé membre
-     * @arg {string} gid - Identifiant du groupe
-     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.remAdmin = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, tools_1.Tools.remove(uid, gid, "admins")];
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de rajouter un porte-parole à un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Elle ne rajoute pas l'utilisateur au groupe.
-     * @arg {string} uid - Identifiant du membre futur porte-parole
-     * @arg {string} gid - Identifiant du groupe
-     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.addSpeaker = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            switch (_a.label) {
-                case 0: return [4 /*yield*/, tools_1.Tools.add(uid, gid, "speakers")];
-                case 1: return [2 /*return*/, _a.sent()];
-            }
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de rétrograder un membre du stade de porte-parole d'un groupe au stade d'utilisateur.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}. Elle dégrade aussi d'un éventuel statut d'administrateur.
-     * @arg {string} uid - Identifiant de l'admin à dégrader (pas supposé valide)
-     * @arg {string} gid - Identifiant du groupe
-     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.remSpeaker = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            switch (_a.label) {
-                case 0: return [4 /*yield*/, tools_1.Tools.remove(uid, gid, "speakers")];
-                case 1: return [2 /*return*/, _a.sent()];
-            }
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet d'ajouter un utilisateur à un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
-     * @arg {string} uid - Identifiant de l'utilisateur à ajouter
-     * @arg {string} gid - Identifiant du groupe
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.addMember = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, tools_1.Tools.add(uid, gid, "members")];
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de supprimer un membre existant d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
-     * Cette fonction supprime tous les droits de l'utilisateur sur le groupe, mais aussi sur les groupes sources si son statut de membre était hérité.
-     * @arg {string} uid - Identifiant de l'ex-membre (pas supposé valide)
-     * @arg {string} gid - Identifiant du groupe
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.remMember = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () {
-            var stack, res, visited, cur_id, _a, _b, _c, _d, _e;
-            return __generator(this, function (_f) {
-                switch (_f.label) {
-                    case 0: return [4 /*yield*/, tools_1.Tools.remove(uid, gid, "members")];
-                    case 1: return [2 /*return*/, _f.sent()];
-                    case 2:
-                        if (!(stack.length > 0)) return [3 /*break*/, 11];
-                        cur_id = stack.pop();
-                        if (!(visited[cur_id] == undefined)) return [3 /*break*/, 10];
-                        visited[cur_id] = true;
-                        _c = res;
-                        if (!_c) return [3 /*break*/, 4];
-                        return [4 /*yield*/, tools_1.Tools.remove(uid, cur_id, "admins")];
-                    case 3:
-                        _c = (_f.sent());
-                        _f.label = 4;
-                    case 4:
-                        _b = _c;
-                        if (!_b) return [3 /*break*/, 6];
-                        return [4 /*yield*/, tools_1.Tools.remove(uid, cur_id, "speakers")];
-                    case 5:
-                        _b = (_f.sent());
-                        _f.label = 6;
-                    case 6:
-                        _a = _b;
-                        if (!_a) return [3 /*break*/, 8];
-                        return [4 /*yield*/, tools_1.Tools.remove(uid, cur_id, "members")];
-                    case 7:
-                        _a = (_f.sent());
-                        _f.label = 8;
-                    case 8:
-                        res = _a;
-                        _e = (_d = stack).concat;
-                        return [4 /*yield*/, basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.childs, cur_id)];
-                    case 9:
-                        _e.apply(_d, [_f.sent()]);
-                        _f.label = 10;
-                    case 10: return [3 /*break*/, 2];
-                    case 11: return [2 /*return*/, res];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet d'ajouter un sympathisant à un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
-     * @arg {string} uid - Identifiant de l'utilisateur à ajouter
-     * @arg {string} gid - Identifiant du groupe
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.addFollower = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, tools_1.Tools.add(uid, gid, "followers")];
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de supprimer un sympathisant d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
-     * @arg {string} uid - Identifiant de l'ex-sympathisant (pas supposé valide)
-     * @arg {string} gid - Identifiant du groupe
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.remFollower = function (uid, gid) {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, tools_1.Tools.remove(uid, gid, "followers")];
-        }); });
-    };
-    /**
-     * @memberof LDAP
-     * @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 LDAP.add} et {@link LDAP.change}, mais aussi {@link Tools.add}
-     * pour gérer les groupes du nouvel utilisateur. Cettte application permet de rajouter des utilisateurs à toutes les catégories du groupe.
-     * @arg {groupData} data - Dictionnaire des informations utilisateurs (voir détail des champs dans ldapConfig.json)
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.create = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            var vals, gid, key_att, vals2, _loop_1, cat;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        vals = {};
-                        // gid de base généré à partir du nom standardisé, pas à partir de l'entrée 'gid' !
-                        try {
-                            tools_1.Tools.generateReadableId(data['name']).then(function (id) {
-                                vals[config_1.ldapConfig.key_id] = id;
-                                vals[config_1.ldapConfig.group['name']] = id;
-                            });
-                        }
-                        catch (err) {
-                            throw "Erreur lors de la génération d'un hruid pour créer un nouveau groupe.";
-                        }
-                        gid = vals[config_1.ldapConfig.key_id];
-                        // Ecriture de toutes les valeurs directement inscrites dans le LDAP
-                        for (key_att in data) {
-                            vals[config_1.ldapConfig.group[key_att]] = data[key_att];
-                        }
-                        ;
-                        return [4 /*yield*/, basics_1.Basics.add("group", vals)];
-                    case 1:
-                        // Appel à la fonction de base
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de la création d'une nouvelle feuille dans l'arbre des groupes.";
-                        }
-                        vals2 = {};
-                        // ?!
-                        vals2[config_1.ldapConfig.group['password']] = "{CRYPT}" + data['password'];
-                        // Génération id aléatoire et test contre le LDAP
-                        try {
-                            tools_1.Tools.generateId(config_1.ldapConfig.group["idNumber"], "group").then(function (id) { vals2[config_1.ldapConfig.group['idNumber']] = id; });
-                        }
-                        catch (err) {
-                            throw "Erreur lors de la génération d'un id numérique pour créer un nouveau groupe.";
-                        }
-                        // Code root
-                        vals2[config_1.ldapConfig.group['cleanFullName']] = data['name'].replace(':', ';').toLowerCase().normalize('UFD');
-                        return [4 /*yield*/, basics_1.Basics.change("group", gid, "add", vals2)];
-                    case 2:
-                        // Inscription des valeurs calculées par effet de bord
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de l'ajout des valeurs intelligentes du nouveau groupe.";
-                        }
-                        ["posixGroup", "brGroup"].forEach(function (cst) {
-                            var vals3 = {};
-                            vals3[config_1.ldapConfig.group['classes']] = cst;
-                            basics_1.Basics.change("group", gid, "add", vals3).then(function (res) {
-                                if (!res) {
-                                    throw "Erreur lors de l'ajout des valeurs constantes du nouveau groupe.";
-                                }
-                            });
-                        });
-                        _loop_1 = function (cat) {
-                            data[cat].forEach(function (uid) {
-                                tools_1.Tools.add(uid, gid, cat).then(function (res) {
-                                    if (!res) {
-                                        throw "Erreur de l'ajout d'un membre au nouveau groupe.";
-                                    }
-                                });
-                            });
-                        };
-                        // Utilisation des fonctions adaptées pour assurer la cohérence de l'ensemble
-                        for (cat in config_1.categories) {
-                            _loop_1(cat);
-                        }
-                        return [2 /*return*/, true];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui supprime un groupe du LDAP.
-     * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. A modifier une fois que le LDAP incluerait les groupes administres par une utilisateur.
-     * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} 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
-     * @async
-     * @static
-     */
-    Group["delete"] = function (gid) {
-        return __awaiter(this, void 0, void 0, function () {
-            var profil, _loop_2, _i, categories_1, cat, err_1;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        _a.trys.push([0, 3, , 4]);
-                        return [4 /*yield*/, Group.peek(gid)];
-                    case 1:
-                        profil = _a.sent();
-                        _loop_2 = function (cat) {
-                            profil[config_1.ldapConfig.group[cat]].forEach(function quickPartRemUser(uid) {
-                                return __awaiter(this, void 0, void 0, function () {
-                                    var lg;
-                                    return __generator(this, function (_a) {
-                                        switch (_a.label) {
-                                            case 0: return [4 /*yield*/, tools_1.Tools.get(uid, "user", cat)];
-                                            case 1:
-                                                lg = _a.sent();
-                                                if (!lg.includes(gid)) return [3 /*break*/, 3];
-                                                return [4 /*yield*/, basics_1.Basics.change("user", uid, "del", config_1.ldapConfig.user[cat])];
-                                            case 2:
-                                                // Supprime tous les groupes
-                                                if (!(_a.sent())) {
-                                                    throw "Erreur lors de la suppression de tous les groupes du membre.";
-                                                }
-                                                // Les rajoute un par un, sauf pour le groupe supprimé
-                                                lg.forEach(function (id) {
-                                                    if (id != gid) {
-                                                        tools_1.Tools.add(uid, id, cat).then(function (res) {
-                                                            if (!res) {
-                                                                throw "Erreur lors du ré-ajout des autres groupes";
-                                                            }
-                                                        });
-                                                    }
-                                                });
-                                                _a.label = 3;
-                                            case 3: return [2 /*return*/];
-                                        }
-                                    });
-                                });
-                            });
-                        };
-                        for (_i = 0, categories_1 = config_1.categories; _i < categories_1.length; _i++) {
-                            cat = categories_1[_i];
-                            _loop_2(cat);
-                        }
-                        return [4 /*yield*/, basics_1.Basics.clear("group", gid)];
-                    case 2:
-                        // Elimination
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes.";
-                        }
-                        return [2 /*return*/, true];
-                    case 3:
-                        err_1 = _a.sent();
-                        throw "Erreur lors de l'obtention du profil d'un groupe pour le supprimer.";
-                    case 4: return [2 /*return*/];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui édite un groupe existant dans le LDAP. Sans influence sur ses membres ou admins.
-     * @desc Appelle {@link Tools.edit}.
-     * @arg {groupData} data - Dictionnaire des informations du groupe.
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Group.edit = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, tools_1.Tools.edit("group", data)];
-                }
-                catch (err) {
-                    throw "Erreur lors de la modification d'un groupe.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    return Group;
-}());
-exports.Group = Group;
diff --git a/src/ldap/export/user.js b/src/ldap/export/user.js
deleted file mode 100644
index 0828e17ee92da099362a25b5b42b91ba185315f4..0000000000000000000000000000000000000000
--- a/src/ldap/export/user.js
+++ /dev/null
@@ -1,332 +0,0 @@
-"use strict";
-/**
- * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
- * @author hawkspar
- */
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __generator = (this && this.__generator) || function (thisArg, body) {
-    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
-    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
-    function verb(n) { return function (v) { return step([n, v]); }; }
-    function step(op) {
-        if (f) throw new TypeError("Generator is already executing.");
-        while (_) try {
-            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
-            if (y = 0, t) op = [0, t.value];
-            switch (op[0]) {
-                case 0: case 1: t = op; break;
-                case 4: _.label++; return { value: op[1], done: false };
-                case 5: _.label++; y = op[1]; op = [0]; continue;
-                case 7: op = _.ops.pop(); _.trys.pop(); continue;
-                default:
-                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
-                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
-                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
-                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
-                    if (t[2]) _.ops.pop();
-                    _.trys.pop(); continue;
-            }
-            op = body.call(thisArg, _);
-        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
-        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
-    }
-};
-exports.__esModule = true;
-var config_1 = require("../internal/config");
-exports.userData = config_1.userData;
-var basics_1 = require("../internal/basics");
-var tools_1 = require("../internal/tools");
-var User = /** @class */ (function () {
-    /**
-     * @memberof LDAP
-     * @class User
-     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs.
-     * @summary Constructeur vide.
-     */
-    function User() {
-    }
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui renvoit les infos de base relatives à un utilisateur particulier.
-     * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link userData}.
-     * @arg {string} uid - Identifiant de l'utilisateur, supposé valide.
-     * @return {Promise(userData)} Informations recueillies au format {@link userData}.
-     * @static
-     * @async
-     */
-    User.peek = function (uid) {
-        return __awaiter(this, void 0, void 0, function () {
-            var data, _a, _b, _i, cat, _c, _d, err_1;
-            return __generator(this, function (_e) {
-                switch (_e.label) {
-                    case 0:
-                        _e.trys.push([0, 6, , 7]);
-                        return [4 /*yield*/, tools_1.Tools.peek("user", uid, config_1.userData)];
-                    case 1:
-                        data = _e.sent();
-                        _a = [];
-                        for (_b in config_1.categories)
-                            _a.push(_b);
-                        _i = 0;
-                        _e.label = 2;
-                    case 2:
-                        if (!(_i < _a.length)) return [3 /*break*/, 5];
-                        cat = _a[_i];
-                        _c = data;
-                        _d = cat;
-                        return [4 /*yield*/, basics_1.Basics.searchSingle("group", config_1.ldapConfig.group[cat], "*", config_1.ldapConfig.group[cat] + "=" + uid)];
-                    case 3:
-                        _c[_d] = _e.sent();
-                        _e.label = 4;
-                    case 4:
-                        _i++;
-                        return [3 /*break*/, 2];
-                    case 5: return [2 /*return*/, data];
-                    case 6:
-                        err_1 = _e.sent();
-                        throw "Error while peeking a user.";
-                    case 7: return [2 /*return*/];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui retrouve les uid des paxs validant les critères de recherche. Utiliser {@link User.peek} au cas par cas après pour obtenir les vraies infos.
-     * @desc Cette fonction utilise {@link Tools.search}.
-     * @arg {userData} 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 exemple pour chercher un membre
-     * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
-     * @return {Promise(string[])} gids des profils qui "match" les critères proposés.
-     * @static
-     * @async
-     */
-    User.search = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, tools_1.Tools.search("user", data)];
-                }
-                catch (err) {
-                    throw "Erreur lors de la recherche approximative d'un utilisateur.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui créé un nouvel utilisateur dans le LDAP.
-     * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Tools.add} pour gérer les groupes du nouvel utilisateur.
-     * @arg {userData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis.
-     * Cette application permet de rejoindre des groupes en masse pour toute catégorie.
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    User.create = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            var vals, uid, key_att, _loop_1, key_att, vals3, _a, _b, err_2, _i, categories_1, cat, _c, _d, gid;
-            return __generator(this, function (_e) {
-                switch (_e.label) {
-                    case 0:
-                        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
-                        try {
-                            tools_1.Tools.generateUid(data['givenName'], data['lastName'], data['birthdate']).then(function (id) { vals[config_1.ldapConfig.key_id] = id; });
-                        }
-                        catch (err) {
-                            throw "Erreur lors de la génération d'un hruid pour un nouvel utilisateur.";
-                        }
-                        uid = vals[config_1.ldapConfig.key_id];
-                        // Génère une erreur si un champ n'est pas rempli
-                        for (key_att in data) {
-                            // Ecriture de toutes les valeurs uniques
-                            if (!Array.isArray(data[key_att])) {
-                                vals[config_1.ldapConfig.user[key_att]] = data[key_att];
-                            }
-                        }
-                        return [4 /*yield*/, basics_1.Basics.add("user", vals)];
-                    case 1:
-                        // Appel à la fonction de base
-                        if (!(_e.sent())) {
-                            throw "Erreur de l'ajout de la feuille à l'arbre utilisateur.";
-                        }
-                        _loop_1 = function (key_att) {
-                            // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples
-                            if (Array.isArray(data[key_att])) {
-                                // On rajoute chaque valeur en entrée
-                                data[key_att].forEach(function (val) {
-                                    var vals2 = {};
-                                    vals2[config_1.ldapConfig.user[key_att]] = val;
-                                    basics_1.Basics.change("user", uid, "add", vals2).then(function (res) {
-                                        if (!res) {
-                                            throw "Erreur lors de l'ajout d'une valeur pour un champ à valeurs multiples à la feuille du nouvel utilisateur.";
-                                        }
-                                    });
-                                });
-                            }
-                        };
-                        for (key_att in data) {
-                            _loop_1(key_att);
-                        }
-                        vals3 = {};
-                        // ldapConfiguration du mot de passe utilisateur
-                        // Le préfixe {CRYPT} signifie que le mdp est hashé dans OpenLDAP voir : https://www.openldap.org/doc/admin24/security.html 
-                        vals3[config_1.ldapConfig.user['password']] = "{CRYPT}" + data['password'];
-                        // Ecriture d'un surnom s'il y a lieu
-                        if ((data['nickname'] != undefined) && (data['nickname'] != '')) {
-                            vals3[config_1.ldapConfig.user['nickname']] = data['nickname'];
-                        }
-                        _e.label = 2;
-                    case 2:
-                        _e.trys.push([2, 4, , 5]);
-                        // Génération id aléatoire unique
-                        _a = vals3;
-                        _b = config_1.ldapConfig.user['id'];
-                        return [4 /*yield*/, tools_1.Tools.generateId(config_1.ldapConfig.user['id'], "user")];
-                    case 3:
-                        // Génération id aléatoire unique
-                        _a[_b] = _e.sent();
-                        return [3 /*break*/, 5];
-                    case 4:
-                        err_2 = _e.sent();
-                        throw "Erreur lors de la génération d'un id numérique pour un nouvel utilisateur.";
-                    case 5:
-                        // Code root
-                        vals3[config_1.ldapConfig.user['cleanFullName']] = data['fullName'].replace(':', ';').toLowerCase().normalize('UFD');
-                        return [4 /*yield*/, basics_1.Basics.change("user", uid, "add", vals3)];
-                    case 6:
-                        // Inscription des valeurs calculées
-                        if (!(_e.sent())) {
-                            throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur.";
-                        }
-                        ["posixAccount", "shadowAccount", "brUser"].forEach(function (cst) {
-                            var val3 = {};
-                            vals3[config_1.ldapConfig.user['class']] = cst;
-                            basics_1.Basics.change("user", uid, "add", vals3).then(function (res) {
-                                if (!res) {
-                                    throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur.";
-                                }
-                            });
-                        });
-                        // Ajout dans les groupes à la catégorie voulue
-                        for (_i = 0, categories_1 = config_1.categories; _i < categories_1.length; _i++) {
-                            cat = categories_1[_i];
-                            for (_c = 0, _d = data[cat]; _c < _d.length; _c++) {
-                                gid = _d[_c];
-                                tools_1.Tools.add(uid, gid, cat);
-                            }
-                        }
-                        return [2 /*return*/, true];
-                }
-            });
-        });
-    };
-    //------------------------------------------------------------------------------------------------------------------------
-    // Fonctions de suppression TBT
-    //------------------------------------------------------------------------------------------------------------------------
-    /**
-     * @memberof LDAP
-     * @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 LDAP.clear} bien sûr, mais aussi {@link Tools.remove} 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
-     * @async
-     * @static
-     */
-    User["delete"] = function (uid) {
-        return __awaiter(this, void 0, void 0, function () {
-            var profil, _loop_2, _i, categories_2, cat, err_3;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        _a.trys.push([0, 2, , 3]);
-                        return [4 /*yield*/, User.peek(uid)];
-                    case 1:
-                        profil = _a.sent();
-                        _loop_2 = function (cat) {
-                            profil[config_1.ldapConfig.user[cat]].forEach(function (gid) {
-                                return __awaiter(this, void 0, void 0, function () {
-                                    var lm;
-                                    return __generator(this, function (_a) {
-                                        switch (_a.label) {
-                                            case 0: return [4 /*yield*/, tools_1.Tools.get(gid, "group", cat)];
-                                            case 1:
-                                                lm = _a.sent();
-                                                if (!lm.includes(uid)) return [3 /*break*/, 3];
-                                                return [4 /*yield*/, basics_1.Basics.change("group", gid, "del", config_1.ldapConfig.group[cat])];
-                                            case 2:
-                                                // Supprime tous les membres
-                                                if (!(_a.sent())) {
-                                                    throw "Erreur lors de la suppression de tous les membres du groupe.";
-                                                }
-                                                // Les rajoute un par un, sauf pour le supprimé
-                                                lm.forEach(function (id) {
-                                                    if (id != uid) {
-                                                        tools_1.Tools.add(id, gid, cat).then(function (res) {
-                                                            if (!res) {
-                                                                throw "Erreur lors du ré-ajout d'un autre membre";
-                                                            }
-                                                        });
-                                                    }
-                                                });
-                                                _a.label = 3;
-                                            case 3: return [2 /*return*/];
-                                        }
-                                    });
-                                });
-                            });
-                        };
-                        for (_i = 0, categories_2 = config_1.categories; _i < categories_2.length; _i++) {
-                            cat = categories_2[_i];
-                            _loop_2(cat);
-                        }
-                        return [3 /*break*/, 3];
-                    case 2:
-                        err_3 = _a.sent();
-                        throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer.";
-                    case 3:
-                        // Elimination
-                        if (!basics_1.Basics.clear("user", uid)) {
-                            throw "Erreur lors de la suppression de l'utilisateur.";
-                        }
-                        return [2 /*return*/, true];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui édite un utilisateur existant dans le LDAP.
-     * @desc Appelle simplement {@link Tools.edit}. Sans effet sur les groupes de l'utilisateur concerné.
-     * @arg {userData} data - Dictionnaire des informations utilisateurs
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    User.edit = function (data) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, tools_1.Tools.edit("user", data)];
-                }
-                catch (err) {
-                    throw "Erreur lors de la modification d'un utilisateur.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    return User;
-}());
-exports.User = User;
diff --git a/src/ldap/internal/config.ts b/src/ldap/internal/config.ts
index 79c3b7da0bf1cc2b7706fdb68c9339d8d540df57..4924c34c41df60fdcf5e89c67e5bce54d1f9ab16 100644
--- a/src/ldap/internal/config.ts
+++ b/src/ldap/internal/config.ts
@@ -10,10 +10,10 @@ import fs from 'fs';
 import path from 'path';
 import colors from 'colors';
 import dotenv from 'dotenv';
-dotenv.config({ path: path.resolve(__dirname, '..', '..', '..', '.env') });
+dotenv.config({ path: path.resolve("/"+__dirname, '..', '..', '..', './.env') });
 
 // Point central ; tous les champs de la BDD sont 'cachés' dans config.json et pas visibles directement
-let path_config = path.resolve(__dirname, '..', '..', '..', 'ldap_config.json');
+let path_config = path.resolve("/"+__dirname, '..', '..', '..', './ldap_config.json');
 console.log(colors.cyan("Loading LDAP config file from "+path_config));
 export const ldapConfig = JSON.parse(fs.readFileSync(path_config).toString());
 
@@ -61,7 +61,7 @@ export class userData {
     givenName?: string;
     lastName?: string;
     nickname?: string;
-    gender?: 'M'|'F';
+    gender?: 'M'|'F'|'U';
     photo?: string;
     phone?: string;
     address?: string;
diff --git a/src/ldap/internal/tools.js b/src/ldap/internal/tools.js
deleted file mode 100644
index a1748de5b358a8444dbbedc7af6ff0e550ec30cc..0000000000000000000000000000000000000000
--- a/src/ldap/internal/tools.js
+++ /dev/null
@@ -1,509 +0,0 @@
-"use strict";
-/**
- * @file Ce fichier regroupe les fonctions génériques de recherche et de test utiles, mais trop puissantes pour être exportées directement.
- * @author hawkspar
- */
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __generator = (this && this.__generator) || function (thisArg, body) {
-    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
-    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
-    function verb(n) { return function (v) { return step([n, v]); }; }
-    function step(op) {
-        if (f) throw new TypeError("Generator is already executing.");
-        while (_) try {
-            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
-            if (y = 0, t) op = [0, t.value];
-            switch (op[0]) {
-                case 0: case 1: t = op; break;
-                case 4: _.label++; return { value: op[1], done: false };
-                case 5: _.label++; y = op[1]; op = [0]; continue;
-                case 7: op = _.ops.pop(); _.trys.pop(); continue;
-                default:
-                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
-                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
-                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
-                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
-                    if (t[2]) _.ops.pop();
-                    _.trys.pop(); continue;
-            }
-            op = body.call(thisArg, _);
-        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
-        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
-    }
-};
-exports.__esModule = true;
-// Toutes les entrées utilisateur sont escapées par sécurité
-var ldap_escape_1 = require("ldap-escape");
-// Imports internes
-var config_1 = require("./config");
-var basics_1 = require("./basics");
-//------------------------------------------------------------------------------------------------------------------------
-// Fonctions intermédiaires TBT
-//------------------------------------------------------------------------------------------------------------------------
-var Tools = /** @class */ (function () {
-    /**
-     * @memberof LDAP
-     * @class Tools
-     * @classdesc Cette classe contient des fonctions intermédiaires qui ne sont pas destinées à être utilisées dans les resolvers.
-     * @summary Constructeur vide.
-     */
-    function Tools() {
-    }
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui renvoit toutes les infos relatives à un groupe ou un utilisateur particulier.
-     * @desc Cette fonction utilise {@link LDAP.search} avec des attributs prédéfinis. Elle est naïve et n'opère pas de récursion.
-     * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData})
-     * @arg {string} domain - Domaine de la recherche (utilisateur ou groupe)
-     * @arg {string} id - Identifiant de la feuille cherchée (uid ou gid)
-     * @return {Promise(T)} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe tel que défini par le paramètre T.
-     * @static
-     * @async
-     */
-    Tools.peek = function (domain, id, type) {
-        return __awaiter(this, void 0, void 0, function () {
-            var dirtyKeys, cleanData, attr, dirtyData, uncleanKey, _i, _a, cleanKey;
-            return __generator(this, function (_b) {
-                switch (_b.label) {
-                    case 0:
-                        dirtyKeys = config_1.ldapConfig[domain];
-                        cleanData = new type();
-                        attr = Object.keys(dirtyKeys).map(function (key) { return dirtyKeys[key]; });
-                        return [4 /*yield*/, basics_1.Basics.searchMultiple(domain, attr, id)];
-                    case 1:
-                        dirtyData = (_b.sent())[0];
-                        console.log(dirtyData);
-                        console.log(cleanData);
-                        // Rename output
-                        for (uncleanKey in dirtyData) {
-                            for (_i = 0, _a = Object.keys(cleanData); _i < _a.length; _i++) {
-                                cleanKey = _a[_i];
-                                console.log(cleanKey);
-                                if (uncleanKey == dirtyKeys[cleanKey]) {
-                                    cleanData[cleanKey] = dirtyData[uncleanKey];
-                                }
-                            }
-                        }
-                        return [2 /*return*/, cleanData];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui retrouve les id des paxs ou groupes validant les critères de recherche. Etape vers vrai TOL (Trombino On Line).
-     * Utiliser {@link peekUser} au cas par cas après pour obtenir les vraies infos.
-     * @desc Cette fonction utilise {@link LDAP.search} 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. Va crasher si un champ n'est pas dans ldapConfig.
-     * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData})
-     * @arg {"us"|"gr"} domain - Domaine de la recherche (utilisateur ou groupe)
-     * @arg {userData | groupData} 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 exemple pour chercher un membre
-     * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
-     * @return {Promise(string[])} ids des profils qui "match" les critères proposés.
-     * @static
-     * @async
-     */
-    Tools.search = function (domain, data) {
-        return __awaiter(this, void 0, void 0, function () {
-            var filter, key;
-            return __generator(this, function (_a) {
-                filter = "";
-                // Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfinis dans ldapConfig encore
-                for (key in data) {
-                    if ((data[key] != undefined) && (data[key] != '')) {
-                        if (!Array.isArray(data[key])) {
-                            data[key] = [data[key]];
-                        } // Génération systématique d'une liste de valeurs à rechercher
-                        // Iteration pour chaque valeur fournie par l'utilisateur
-                        data[key].forEach(function (val) {
-                            // Traduction en language LDAP
-                            var attribute = "";
-                            attribute = config_1.ldapConfig[domain][key];
-                            // Escape user input
-                            val = ldap_escape_1["default"].filter("${fil}", { fil: val });
-                            // Creation incrémentale du filtre
-                            filter = "(&" + filter + "(|(" + attribute + "=" + val + ")" + // On cherche la valeur exacte
-                                "(" + attribute + "=*" + val + ")" + // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs)
-                                "(" + attribute + "=*" + val + "*)" + // La valeur du milieu avec des trucs avant et après
-                                "(" + attribute + "=" + val + "*)))"; // La valeur du début avec des trucs après
-                        });
-                    }
-                }
-                // Appel avec filtre de l'espace 
-                return [2 /*return*/, basics_1.Basics.searchSingle(domain, config_1.ldapConfig.key_id, null, filter)];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui édite un groupe ou utilisateur existant dans le LDAP. N'agit pas sur l'apprtenance à un groupe.
-     * @desc Appelle {@link LDAP.change}.
-     * @arg {"us"|"gr"} domain - Domaine de l'opération' (utilisateur ou groupe).
-     * @arg {userData | groupData} data - Dictionnaire avec les nouvelles valeurs de la feuille.
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon.
-     * @async
-     * @static
-     */
-    Tools.edit = function (domain, data) {
-        return __awaiter(this, void 0, void 0, function () {
-            var id, id, dirtyKeys, dirtyData;
-            return __generator(this, function (_a) {
-                if (domain == "user") {
-                    id = data['uid'];
-                }
-                else {
-                    id = data['gid'];
-                }
-                dirtyKeys = config_1.ldapConfig[domain];
-                dirtyData = {};
-                Object.keys(data).forEach(function (key) {
-                    // Some values edit can't change
-                    if (!['readPerm', 'writePerm', 'groups', 'groupsIsAdmin', 'followers', 'members', 'speakers', 'admins'].includes(key)) {
-                        dirtyData[dirtyKeys.key] = data[key];
-                    }
-                });
-                return [2 /*return*/, basics_1.Basics.change(domain, id, "replace", dirtyData)];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet d'ajouter un utilisateur à une catégorie  d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}.
-     * Cette fonction ne créé pas de doublon et opère conjointement dans les deux arbres "group" et "user"
-     * @arg {string} uid - Identifiant du futur membre
-     * @arg {string} gid - Identifiant du groupe
-     * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower)
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Tools.add = function (uid, gid, category) {
-        return __awaiter(this, void 0, void 0, function () {
-            var lu, catName, err_1, lg, catName, err_2;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        _a.trys.push([0, 4, , 5]);
-                        return [4 /*yield*/, Tools.get(gid, "group", category)];
-                    case 1:
-                        lu = _a.sent();
-                        catName = config_1.ldapConfig.group[category];
-                        if (!!lu.includes(uid)) return [3 /*break*/, 3];
-                        return [4 /*yield*/, basics_1.Basics.change("group", gid, "add", catName)];
-                    case 2:
-                        // Ajoute l'utilisateur dans la catégorie concernée
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de la modification dans l'arbre des groupes pour ajouter un membre dans la catégorie voulue.";
-                        }
-                        _a.label = 3;
-                    case 3: return [3 /*break*/, 5];
-                    case 4:
-                        err_1 = _a.sent();
-                        throw "Erreur pour obtenir une liste de membres d'une catégorie d'un groupe pour ajouter un membre de cette categorie du groupe.";
-                    case 5:
-                        _a.trys.push([5, 9, , 10]);
-                        return [4 /*yield*/, Tools.get(uid, "user", category)];
-                    case 6:
-                        lg = _a.sent();
-                        catName = config_1.ldapConfig.user[category];
-                        if (!!lg.includes(gid)) return [3 /*break*/, 8];
-                        return [4 /*yield*/, basics_1.Basics.change("user", uid, "add", catName)];
-                    case 7:
-                        // Ajoute l'utilisateur dans la categorie voulue
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de l'ajout d'un utilisateur dans une catégorie d'un groupe.";
-                        }
-                        _a.label = 8;
-                    case 8: return [2 /*return*/, true];
-                    case 9:
-                        err_2 = _a.sent();
-                        throw "Erreur pour obtenir une liste de groupes d'une categorie d'un membre pour ajouter un groupe de cette category pour le membre.";
-                    case 10: return [2 /*return*/];
-                }
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui permet de supprimer un membre d'une catégorie existant d'un groupe.
-     * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}.
-     * @arg {string} uid - Identifiant de l'ex-membre
-     * @arg {string} gid - Identifiant du groupe
-     * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower)
-     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
-     * @async
-     * @static
-     */
-    Tools.remove = function (uid, gid, category) {
-        return __awaiter(this, void 0, void 0, function () {
-            var lu, catName, err_3, lg, catName, err_4;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        _a.trys.push([0, 4, , 5]);
-                        return [4 /*yield*/, Tools.get(gid, "group", category)];
-                    case 1:
-                        lu = _a.sent();
-                        catName = config_1.ldapConfig.group[category];
-                        if (!lu.includes(uid)) return [3 /*break*/, 3];
-                        return [4 /*yield*/, basics_1.Basics.change("group", gid, "del", catName)];
-                    case 2:
-                        // Supprime tous les utilisateurs
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de la suppression de tous les membres d'une catégorie du groupe.";
-                        }
-                        // Les rajoute un par un, sauf pour le supprimé
-                        lu.forEach(function (id) {
-                            if (id != uid) {
-                                Tools.add(id, gid, category).then(function (res) {
-                                    if (!res) {
-                                        throw "Erreur lors du ré-ajout d'un autre membre d'une catégorie.";
-                                    }
-                                });
-                            }
-                        });
-                        _a.label = 3;
-                    case 3: return [3 /*break*/, 5];
-                    case 4:
-                        err_3 = _a.sent();
-                        throw "Erreur pour obtenir une liste de membres d'une catégorie d'un groupe pour supprimer un membre de cette categorie du groupe.";
-                    case 5:
-                        _a.trys.push([5, 9, , 10]);
-                        return [4 /*yield*/, Tools.get(uid, "user", category)];
-                    case 6:
-                        lg = _a.sent();
-                        catName = config_1.ldapConfig.user[category];
-                        if (!lg.includes(gid)) return [3 /*break*/, 8];
-                        return [4 /*yield*/, basics_1.Basics.change("user", uid, "del", catName)];
-                    case 7:
-                        // Supprime tous les groupes de la catégorie pour l'utilisateur
-                        if (!(_a.sent())) {
-                            throw "Erreur lors de la suppression de tous les groupes d'un membre.";
-                        }
-                        // Les rajoute un par un, sauf pour le supprimé
-                        lg.forEach(function (id) {
-                            if (id != uid) {
-                                Tools.add(id, gid, category).then(function (res) {
-                                    if (!res) {
-                                        throw "Erreur lors du ré-ajout d'un autre groupe.";
-                                    }
-                                });
-                            }
-                        });
-                        _a.label = 8;
-                    case 8: return [2 /*return*/, true];
-                    case 9:
-                        err_4 = _a.sent();
-                        throw "Erreur pour obtenir une liste de groupes d'une categorie d'un membre pour supprimer un groupe de cette category pour le membre.";
-                    case 10: return [2 /*return*/];
-                }
-            });
-        });
-    };
-    /**
-     * @callback changeValueCallback
-     * @param {string} id - Id à modifier
-     * @param {number} n - Nombre d'itérations
-     * @return {string} Nouveau id
-     */
-    /**
-     * @memberof LDAP
-     * @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.search} pour vérifier
-     * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut
-     * dans le dn fourni.
-     * @param {string} value - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération
-     * @param {string} attribute - Attribut à tester
-     * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique
-     * @param {changeValueCallback} changeValue - 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 {number} n [0] - Nombre d'itérations (à initialiser à 0)
-     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
-     * @static
-     * @async
-     */
-    Tools.ensureUnique = function (value, attribute, domain, changeValue, n) {
-        if (n === void 0) { n = 0; }
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                // Recherche d'autres occurences de l'id
-                try {
-                    return [2 /*return*/, basics_1.Basics.searchSingle(domain, config_1.ldapConfig.key_id, null, "(" + attribute + "=" + value + ")").then(function (matches) {
-                            if (!matches) {
-                                throw "";
-                            }
-                            else if (matches.length = 0) {
-                                return value;
-                            }
-                            else {
-                                return Tools.ensureUnique(changeValue(value, n + 1), attribute, domain, changeValue, n + 1);
-                            }
-                        })];
-                }
-                catch (err) {
-                    throw "Erreur lors de la recherche d'une valeur pour assurer son unicité.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
-     * @desc Limité à un appel à {@link Tools.ensureUnique} 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
-     * @async
-     */
-    Tools.generateUid = function (givenName, lastName, promotion) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    // normalize et lowerCase standardisent le format
-                    return [2 /*return*/, Tools.ensureUnique((givenName + '.' + lastName).toLowerCase().normalize('UFD'), config_1.ldapConfig.key_id, "user", function (id, n) {
-                            if (n = 1) {
-                                id += '.' + promotion;
-                            } // Si prénom.nom existe déjà, on rajoute la promo
-                            else if (n = 2) {
-                                id += '.' + (n - 1).toString();
-                            } // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1
-                            else if (n > 2) {
-                                id += n;
-                            } // Ensuite on continue .123, .1234, etc...
-                            return id;
-                        })];
-                }
-                catch (err) {
-                    throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid).";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Cette fonction génère un id lisible, puis le fait évoluer jusqu'à ce qu'il soit unique.
-     * @desc Limité à un appel à {@link Tools.ensureUnique} 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
-     * @async
-     */
-    Tools.generateReadableId = function (name) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    // normalize et lowerCase standardisent le format
-                    return [2 /*return*/, Tools.ensureUnique(name.toLowerCase().normalize('UFD'), config_1.ldapConfig.key_id, "group", function (id, n) {
-                            if (n = 1) {
-                                id += '.' + n.toString();
-                            } // Si nom existe déjà, on essaie nom.1
-                            else if (n > 1) {
-                                id += n.toString();
-                            } // Ensuite on continue .12, .123, etc...
-                            return id;
-                        })];
-                }
-                catch (err) {
-                    throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid).";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @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 {string} attribut - Intitulé exact de l'id concerné
-     * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique
-     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
-     * @static
-     * @async
-     */
-    Tools.generateId = function (attribut, domain) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                try {
-                    return [2 /*return*/, Tools.ensureUnique("0", attribut, domain, function (id, n) { return Math.floor((Math.random() * 100000) + 1).toString(); })];
-                }
-                catch (err) {
-                    throw "Erreur lors de l'assurance de l'unicité d'un unique identifier numérique.";
-                }
-                return [2 /*return*/];
-            });
-        });
-    };
-    /**
-     * @memberof LDAP
-     * @summary Fonction qui retrouve les utilisateurs ou groupes respectivement correspondant à un groupe ou un utilisateur de la même catégorie.
-     * @desc Cette fonction utilise {@link LDAP.search} et va directement à la feuille de l'utilisateur ou du groupe interrogé.
-     * Pour autant, elle est moins naïve qu'elle en a l'air. Elle ne gère ni la descente des admins ni la remontée des membres et renvoit une réponse naïve.
-     * @param {string} id - Identifiant du groupe ou de l'individu à interroger (supposé valide)
-     * @param {"user"|"group"} domain - Arbre à interroger
-     * @param {"admins"|"speakers"|"members"|"followers"} category - Catégorie considérée
-     * @return {Promise(string[])} Liste des id de groupes ou d'utilisateurs de la bonne catégorie associé à l'id
-     * @static
-     * @async
-     */
-    Tools.get = function (id, domain, category) {
-        return __awaiter(this, void 0, void 0, function () {
-            var stack, res, visited, cur_id, _a, _b, _c, _d, _e, _f, err_5;
-            return __generator(this, function (_g) {
-                switch (_g.label) {
-                    case 0:
-                        _g.trys.push([0, 11, , 12]);
-                        return [4 /*yield*/, basics_1.Basics.searchSingle(domain, config_1.ldapConfig[domain][category], id)];
-                    case 1: return [2 /*return*/, _g.sent()];
-                    case 2: return [2 /*return*/, _g.sent()];
-                    case 3:
-                        stack = [];
-                        res = [];
-                        visited = {};
-                        stack.push(id);
-                        _g.label = 4;
-                    case 4:
-                        if (!(stack.length > 0)) return [3 /*break*/, 10];
-                        cur_id = stack.pop();
-                        if (!(visited[cur_id] == undefined)) return [3 /*break*/, 9];
-                        visited[cur_id] = true;
-                        _b = (_a = res).concat;
-                        return [4 /*yield*/, basics_1.Basics.searchSingle("group", config_1.ldapConfig.group[category], cur_id)];
-                    case 5:
-                        _b.apply(_a, [_g.sent()]);
-                        if (!(category == "members")) return [3 /*break*/, 7];
-                        _d = (_c = stack).concat;
-                        return [4 /*yield*/, basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.childs, cur_id)];
-                    case 6:
-                        _d.apply(_c, [_g.sent()]);
-                        return [3 /*break*/, 9];
-                    case 7:
-                        _f = (_e = stack).concat;
-                        return [4 /*yield*/, basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.parents, cur_id)];
-                    case 8:
-                        _f.apply(_e, [_g.sent()]);
-                        _g.label = 9;
-                    case 9: return [3 /*break*/, 4];
-                    case 10: return [3 /*break*/, 12];
-                    case 11:
-                        err_5 = _g.sent();
-                        throw "Erreur lors d'une recherche générique d'un membre d'une certaine catégorie d'un groupe.";
-                    case 12: return [2 /*return*/];
-                }
-            });
-        });
-    };
-    return Tools;
-}());
-exports.Tools = Tools;
diff --git a/src/ldap/test.js b/src/ldap/test.js
index 5b8f1d116219132b78654da1d02dfe7e33206e09..4e547ba4aa294ac5e71fd0065d095dcf9a63e721 100644
--- a/src/ldap/test.js
+++ b/src/ldap/test.js
@@ -1,5 +1,5 @@
-var Group = require("./export/group");
+var Group = require("../../tsbuild/src/ldap/export/group");
 
 console.log(Group.peek("faerix"));
 
-var User = require("./export/group");
\ No newline at end of file
+var User = require("../../tsbuild/src/ldap/export/group");
\ No newline at end of file
diff --git a/tsbuild/db/knex_router.js b/tsbuild/db/knex_router.js
new file mode 100644
index 0000000000000000000000000000000000000000..0066ffd2f6b3b59723ba784e1204eddfb6e884a2
--- /dev/null
+++ b/tsbuild/db/knex_router.js
@@ -0,0 +1,11 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * @file Charge la configuration knexjs adaptée à l'environnement (production ou développement) puis exporte un objet knex permettant les requêtes SQL
+ */
+require('dotenv').config();
+const environment = process.env.TARGET_ENV;
+exports.config = require('./knexfile')[environment];
+console.log("Running Knex configuration '%s'", environment);
+exports.default = require('knex')(exports.config);
+//# sourceMappingURL=knex_router.js.map
\ No newline at end of file
diff --git a/tsbuild/db/knex_router.js.map b/tsbuild/db/knex_router.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..05842febb66fa6404c770c09caedaab86336440c
--- /dev/null
+++ b/tsbuild/db/knex_router.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"knex_router.js","sourceRoot":"","sources":["../../db/knex_router.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;AAE3B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;AAC9B,QAAA,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,CAAC;AAEzD,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,WAAW,CAAC,CAAC;AAE5D,kBAAe,OAAO,CAAC,MAAM,CAAC,CAAC,cAAM,CAAC,CAAC"}
\ No newline at end of file
diff --git a/tsbuild/src/adminview/admin_router.js b/tsbuild/src/adminview/admin_router.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1f375ec4a4e42ddb2d4ad7d56aae0cd77726195
--- /dev/null
+++ b/tsbuild/src/adminview/admin_router.js
@@ -0,0 +1,227 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * @file Ce fichier définit le routage d'URL au sein de l'interface du _backend_.
+ * Les URLs à résoudre ici sont les /adminview/* (et ce sont les seules).
+ *
+ * @desc Cette interface est destinée à n'être accessible qu'aux administrateurs du backend
+ * Filtrage basique : déjà il faut que la personne connaisse l'adresse IP ou le hostname du backend...
+ * L'authentification est basée sur passport avec ldapauth (comme pour les requêtes GraphQL), et
+ * l'autorisation se fait à la main en vérifiant l'appartenance de l'uid à une whitelist.
+ *
+ * Par cette interface admin, on a accès :
+ * - à une API REST fait-maison (peut-être encore à débugger),
+ *      permettant de consulter la base de donnée interne à Sigma, via des requêtes construites avec Knex.
+ *      accessible par les paths `/adminview/db/:table?`
+ * - à GraphQL Voyager, un package qui permet d'afficher une représentation sous forme de graphe du schéma GraphQL,
+ *      acessible par le path `/adminview/voyager`
+ * - à GraphQL Playground, qui permet d'écrire ses propres requêtes GraphQL et de les exécuter.
+ *      il est en fait accessible sans authentification du tout, au path `/graphql`, l'interface admin ne fait que fournir un lien vers ce path
+ *      il est désactivé en production : "When NODE_ENV is set to production, GraphQL Playground (as well as introspection) is disabled as a production best-practice"
+ *      https://www.apollographql.com/docs/apollo-server/features/graphql-playground.html#Configuring-Playground
+ *
+ * @author manifold, kadabra
+ *
+ * @todo check that REST API is finished and functional
+ * @todo Les res.redirect() sont censes supporter les paths relatifs (et donc pas besoin de repreciser /adminview/* a chaque fois)
+ * mais ca marche visiblement pas... Donc j'ai mis les paths absolus dans les res.redirect(). C'est un peu moche... essayer de modifier ca
+ */
+const express_1 = require("express");
+// packages pour l'authentification
+const passport_1 = __importDefault(require("passport"));
+const connect_ensure_login_1 = require("connect-ensure-login");
+const connect_flash_1 = __importDefault(require("connect-flash"));
+// packages pour l'API REST et pour GraphQL Voyager
+const knex_router_1 = __importDefault(require("../../db/knex_router"));
+const middleware_1 = require("graphql-voyager/middleware");
+//loads environment variables from (hidden) .env file
+const dotenv_1 = __importDefault(require("dotenv"));
+dotenv_1.default.config();
+let port = process.env.PORT;
+const whitelist = [
+    "gregoire.grzeckowicz",
+    "anatole.romon",
+    "hadrien.renaud",
+    "wilson.jallet",
+    "quentin.chevalier",
+    "guillaume.wang",
+    "oliver.facklam"
+];
+/**
+ * @function ensureIsAdmin
+ * @summary Définit un middleware garantissant que la requête vient bien d'un utilisateur admin authentifié, et redirigeant vers returnTo sinon
+ * @argument String returnTo
+ */
+function ensureIsAdmin(returnTo) {
+    return (req, res, next) => {
+        // ensure that the request was authenticated by passport
+        connect_ensure_login_1.ensureLoggedIn(returnTo);
+        // lookup req.user against whitelist of admin users
+        if (req.user && whitelist.includes(req.user.uid)) {
+            console.log("is an admin");
+            // go on
+            next();
+        }
+        else {
+            console.log("is NOT an admin");
+            req.flash('error: not an admin');
+            req.logout();
+            res.redirect(returnTo);
+        }
+        // go on
+        //next();
+    };
+}
+/**
+ * @desc Création du Express router et setup de middlewares basiques
+ * =================================================================
+ * router: an Express router. https://expressjs.com/en/4x/api.html#router
+ * See also https://scotch.io/tutorials/learn-to-use-the-new-router-in-expressjs-4
+ * = a "sub-middleware stack", a “mini-application" inside the main application
+ *
+ * router automatically inherits from views and 'pug' view engine, that were set in app.ts (app.set(...))
+ */
+const router = express_1.Router();
+//from https://www.npmjs.com/package/connect-flash:
+//"The flash is a special area of the session used for storing messages. Messages are written to the flash and cleared after being displayed to the user."
+router.use(connect_flash_1.default());
+/**
+ * @desc Paths pour l'authentification : login, logout, page d'accueil
+ * ===================================================================
+ * Le login se fait en POST. Faire un GET à la racine / renvoie sur
+ * /login ou sur /admin selon que l'utilisateur est connecté ou non.
+ */
+router.get('/', (req, res) => {
+    res.redirect('/adminview/admin');
+});
+router.get('/avlogin', (req, res) => {
+    // lets pug render adminview/views/login.pug with specified attributes
+    res.render('login', {
+        title: 'Login', port: port,
+        errorMessage: req.flash('error')
+    });
+});
+router.get('/admin', ensureIsAdmin('/adminview/avlogin'), (req, res, next) => {
+    let userName;
+    if (req.user) {
+        userName = req.user.uid;
+    }
+    else {
+        // Une erreur a ce stade peut etre triggered si req.user n'existe pas
+        // mais pour autant on est assures que la personne est bien authentifiee
+        // donc on laisse passer sans déclencher d'erreur 500
+        // (je suis à peu près sûr que ça ne peut jamais arriver ! pour moi si ça arrive c'est ultra bizarre et on ferait mieux de déclencher une erreur ! à tester. --kadabra)
+        /*
+        let err = new Error('Not authorized');
+        res.status(403);
+        next(err);
+        */
+        console.log("Warning: une requête est arrivée à /adminview/admin et req.user n'existe pas");
+        userName = "personne";
+    }
+    res.render('home', {
+        title: 'Home', port: port,
+        userName: userName
+    });
+});
+router.post('/avlogin', passport_1.default.authenticate('ldapauth', {
+    failureRedirect: '/adminview/avlogin',
+    failureFlash: true
+}), (req, res) => {
+    // If this function gets called, authentication was successful.
+    // `req.user` contains the authenticated user.
+    console.log("POST request to /adminview/avlogin: OK, authenticated by LDAP. req.user: ");
+    console.log(req.user);
+    // redirect to /admin
+    // in /admin, user will be looked up against whitelist anyway
+    res.redirect('/adminview/admin');
+});
+router.post('/avlogout', (req, res) => {
+    req.logout();
+    res.redirect('/adminview/admin');
+});
+/**
+ * @desc GraphQL Voyager
+ * =====================
+ * affiche une représentation sous forme de graphe du schema GraphQL
+ */
+router.use('/voyager', ensureIsAdmin('/adminview/avlogin'), middleware_1.express({ endpointUrl: '/graphql' }));
+/**
+ * @desc API REST fait-maison
+ * ==========================
+ * GET `/adminview/db/table_name` renvoie une vue de la table table_name
+ *
+ * GET `/adminview/db/table_name?columns=bla` fait une requete
+ *      SELECT bla FROM table_name
+ * et renvoie un JSON contenant le resultat
+ *
+ * TODO: à tester et rassifier
+ * TODO: je pense qu'on ferait mieux d'utiliser ca plutôt que router.get
+ * https://expressjs.com/en/4x/api.html#router.route
+ */
+router.get('/db?', ensureIsAdmin('/adminview/avlogin'), (req, res) => {
+    let table_name = req.query.table;
+    let columns = req.query.columns;
+    res.redirect(`/adminview/db/${table_name}?columns=${columns}`);
+});
+/**
+ * @function Knex_API: Get table
+ * @summary Effectue une requête pour une table dans la BDD
+ * @argument {string} table_name - La table voulue par l'utilisateur.
+ */
+router.get('/db/:table_name?', ensureIsAdmin('/adminview/avlogin'), (req, res, next) => {
+    // get columns from query
+    let columns;
+    if (req.query.columns) {
+        columns = req.query.columns.split(',');
+    }
+    else {
+        columns = null;
+    }
+    console.log(req.params.table_name);
+    console.log(columns);
+    knex_router_1.default.select(columns).from(req.params.table_name).then(function (table) {
+        res.setHeader("Content-Type", "application/json");
+        res.write(JSON.stringify(table, null, 2));
+        res.end();
+    }, 
+    // the following can only be executed if the previous one failed, since previous one calls res.end()
+    function () {
+        let err = new Error("Bad request: cannot find table " + req.params.table_name);
+        res.status(400);
+        next(err);
+    });
+});
+/**
+ * @desc Error handling
+ * ====================
+ * https://expressjs.com/en/guide/error-handling.html
+ */
+/**
+ * @function Error_404_catcher
+ * @summary Catche les requêtes en dehors des URL acceptées
+ */
+router.use((req, res, next) => {
+    let err = new Error('Not found');
+    res.status(404);
+    next(err);
+});
+/**
+ * @function Error_handler
+ * @summary Gère les erreurs
+ */
+router.use((err, req, res, next) => {
+    console.log("adminview: Entering error handler");
+    console.log(err);
+    //console.log(err.message);
+    //res.status(err.status || 500);
+    res.render('error', {
+        status: res.statusCode,
+        error_message: err.message
+    });
+});
+exports.default = router;
+//# sourceMappingURL=admin_router.js.map
\ No newline at end of file
diff --git a/tsbuild/src/adminview/admin_router.js.map b/tsbuild/src/adminview/admin_router.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..64c165482a41f5d96e880f9c29c68b0f6154f85f
--- /dev/null
+++ b/tsbuild/src/adminview/admin_router.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"admin_router.js","sourceRoot":"","sources":["../../../src/adminview/admin_router.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/app.js b/tsbuild/src/app.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b4bbf29bd3951860734b90989772a70df4ccf1e
--- /dev/null
+++ b/tsbuild/src/app.js
@@ -0,0 +1,276 @@
+"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * @file Initialise et configure le serveur Express sur lequel tourne le back.
+ *
+ * Inclut les middlewares des packages utilisés: apollo-server, passportjs, morgan...
+ * et branche nos propres middleware : l'API GraphQL et l'interface admin du backend (adminview).
+ * Pour comprendre ce que fait chaque package, se référer à leur page sur https://www.npmjs.com.
+ *
+ * On peut considérer que les app.use (et app.get et app.post) sont pattern-matchés et
+ * exécutés séquentiellement. http://expressjs.com/en/guide/using-middleware.html
+ *
+ * @author manifold, kadabra, ofacklam
+ */
+const express_1 = __importDefault(require("express"));
+const body_parser_1 = __importDefault(require("body-parser"));
+// packages pour graphql
+const apollo_server_express_1 = require("apollo-server-express");
+const schema_1 = __importDefault(require("./graphql/schema")); // definition du schéma et des resolvers
+// l'interface admin du backend (adminview)
+const admin_router_1 = __importDefault(require("./adminview/admin_router"));
+// packages pour l'authentification
+const passport_1 = __importDefault(require("passport"));
+require("./config_passport"); // configure passport, pour l'authentification ldap et pour comment gérer les sessions (serializeUser/deserializeUser)
+const express_session_1 = __importDefault(require("express-session"));
+const cors_1 = __importDefault(require("cors"));
+// HTTP request logger
+const morgan_1 = __importDefault(require("morgan"));
+// packages pour pouvoir importer des fichiers de config
+const path_1 = __importDefault(require("path"));
+// config des paramètres de connexion au LDAP
+const config_1 = require("./ldap/internal/config");
+//loads environment variables from (hidden) .env file
+const dotenv_1 = __importDefault(require("dotenv"));
+dotenv_1.default.config();
+/**
+ * @desc Création de l'application Express et setup de middlewares basiques
+ * ========================================================================
+ */
+const app = express_1.default();
+// parse incoming HTTP request bodies, available under the req.body property
+app.use(body_parser_1.default.json()); //parses bodies of media type "application/json"
+app.use(body_parser_1.default.urlencoded({
+    extended: true //use qs library (see https://www.npmjs.com/package/body-parser#bodyparserurlencodedoptions)
+}));
+// ne *pas* inclure de header HTTP publicisant que l'application tourne sous Express
+app.disable('x-powered-by');
+// use morgan (HTTP request logger middleware)
+app.use(morgan_1.default('dev'));
+const FRONTEND_SERVER_URL = process.env.FRONTEND_SERVER_URL;
+// Options de configuration pour le _middleware_ `cors`.
+// CORS = Cross Origin Resource Sharing
+const corsOptions = {
+    //configures the "Access-Control-Allow-Origin" CORS header, declaring that sigma-back wants to make resources accessible to that site (and that site only)
+    origin: FRONTEND_SERVER_URL,
+    //configures the "Access-Control-Allow-Credentials" CORS header, allowing cookies to be included on cross-origin requests
+    credentials: true
+};
+app.use(cors_1.default(corsOptions));
+// respond to "GET /favicon.ico" requests
+// favicon middleware is placed near the top of the middleware stack, to answer favicon requests faster, as they are relatively frequent
+// (plus, they should not have to trigger any authentication middleware)
+const serve_favicon_1 = __importDefault(require("serve-favicon")); // tres tres important :p
+app.use(serve_favicon_1.default(path_1.default.resolve(__dirname, '..', 'assets', 'favicon.ico')));
+/**
+ * @desc Authentification de la requête contre le session-store (cookie)
+ * =====================================================================
+ * Si la requête possède un cookie, on regarde dans la session s'il s'agit d'un cookie valide.
+ * Si oui, on récupère l'uid de l'utilisateur correspondant dans la session.
+ * L'uid qu'on a trouvé est stocké dans req.user, et sera passé à GraphQL, dans le context.
+ * (Si non, on passera quand même dans context un uid spécial signifiant que l'utilisateur n'est pas authentifié. cf la définition de context, plus loin)
+ *
+ * NB : la session ne contient que les correspondances cookie / uid, et rien d'autre.
+ * passport.serializeUser et .deserializeUser servent en théorie à traduire
+ *
+ * https://stackoverflow.com/questions/22052258/what-does-passport-session-middleware-do
+ *
+ * On a un petit peu la meme demarche que l'Option 1 de
+ * https://blog.apollographql.com/a-guide-to-authentication-in-graphql-e002a4039d1
+ */
+/**
+ * it is also here that we define parameters for *session store*. https://redislabs.com/blog/cache-vs-session-store/
+ * configure this right, as express-session docs warns that the default config is not good for prod!!
+ * @todo [critical] configure express-session (session store and other options)
+ * @todo choose a session secret and where to store it
+ * https://www.npmjs.com/package/express-session
+ * Sur l'utilité des flags dans les cookies : https://www.information-security.fr/securite-sites-web-lutilite-flags-secure-httponly/
+ */
+// load data from the session identified by the cookie (if one exists), into req.session
+// on ne manipulera pas req.session directement, on laisser toujours passport le faire pour nous
+app.use(express_session_1.default({
+    secret: "asdfjklkjfdsasdfjklkljfdsa",
+    resave: false,
+    rolling: false,
+    saveUninitialized: true,
+    //store: ,// default is NOT good => @ofacklam est d'avis d'utiliser 'connect-session-knex', comme ca on peut le plug directement dans notre BDD. 
+    cookie: {
+        maxAge: 3600000,
+        //secure: true, // Le cookie ne peut transiter qu'en HTTPS. ATTENTION :  If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express
+        httpOnly: true
+    }
+}));
+app.use(passport_1.default.initialize());
+//passport.session(): load the user object onto req.user if a serialised user object was found in the req.session
+// aucun effet sur les requetes sans cookie ou les requetes avec cookie expired,
+// puisqu'elles ne sont pas dans req.session, puisque non-reconnues par app.use(expressSession(...))
+//(see http://toon.io/understanding-passportjs-authentication-flow/)
+app.use(passport_1.default.session(), (req, res, next) => {
+    let user = req.user ? req.user.uid : "none";
+    console.log(`passport.session(): found user: ${user}, authenticated: ${req.isAuthenticated()}`);
+    next();
+});
+/**
+ * @desc Répondre aux requêtes de connexion par LDAP (venant du front)
+ * ===================================================================
+ * i.e. endpoint for frontend's authentication requests (logins through adminview/avlogin are caught by the router in admin_router.js)
+ * i.e. quand l'utilisateur submit le formulaire de login avec ses identifiants/mdp dans le front
+ *
+ * @todo gérer le cas où une requête à /login est reçue, mais où cette requête contient un cookie valide
+ * @todo vérifier qu'on ne fallthrough pas, i.e. qu'on renvoie une response et qu'on ne trigger pas les middlewares suivants une fois celui-ci terminé
+ * @todo rassify
+ */
+//with custom callback:
+//http://www.passportjs.org/docs/authenticate/#custom-callback
+// http://toon.io/understanding-passportjs-authentication-flow/
+app.post('/login', (req, res, next) => {
+    console.log("Received an authentication request to /login");
+    passport_1.default.authenticate('ldapauth', (err, user, info) => {
+        console.log("| Entering passport.authenticate('ldapauth', - ) callback");
+        // If an exception occurred
+        if (err) {
+            console.log("| Error when trying to passport.authenticate with ldapauth");
+            console.log(err);
+            return res.status(err.status).json({
+                message: "Exception raised in backend process during authentication: " + err,
+                authSucceeded: false
+            });
+            // return next(err); // handle error? or drop request and answer with res.json()?
+        }
+        // If authentication failed, user will be set to false
+        if (!user) {
+            console.log("| Authentication failed, passport.authenticate did not return a user. ");
+            return res.status(401).json({
+                message: "Authentication failed: " + info.message,
+                authSucceeded: false
+            });
+        }
+        req.login(user, (err) => {
+            // If an exception occurred at login
+            if (err) {
+                console.log("| Error when trying to req.login in callback in passport.authenticate('ldapauth', - )");
+                console.log(err);
+                return res.status(err.status).json({
+                    message: "Exception raised in backend process during login: " + err,
+                    authSucceeded: false
+                });
+                // return next(err); // handle error? or drop request and answer with res.json()?
+            }
+            // If all went well
+            console.log("| Authentication succeeded! :)");
+            // passport.authenticate automatically includes a Set-Cookie HTTP header in 
+            // the response. The JSON body is just to signal the frontend that all went well
+            return res.status(200).json({
+                message: 'Authentication succeeded',
+                authSucceeded: true
+            });
+        });
+    })(req, res, next);
+});
+const authorization_1 = require("./graphql/models/authorization");
+const context = ({ req }) => __awaiter(this, void 0, void 0, function* () {
+    // set a special uid for non-authenticated requests
+    // /!\ FOR DEVELOPMENT ONLY: use the one in the ldap_credentials.json file (imported by config.ts)
+    // for production, replace with a "publicUser" or "notLoggedInUser" or something.
+    let uid = config_1.credentialsLdapConfig.dn.split("=")[1].split(",")[0];
+    console.log("Responding to graphql request...");
+    console.log(`
+    | User: ${req.user ? req.user.uid : "none"}
+    | Authenticated: ${req.isAuthenticated()}
+    `.trim());
+    if (req.isAuthenticated() && req.user) {
+        console.log("graphql API is receiving a request from an authenticated user! \\o/");
+        try {
+            uid = req.user.uid;
+        }
+        catch (err) {
+            console.log("Error: req is authenticated, but pb when trying to extract uid from req.user. Probably user was either not serialized or not deserialized properly");
+            console.log(err);
+        }
+    }
+    console.log(`Constructing context with uid = ${uid}`);
+    /*return {
+        request: req,
+        user: { uid: uid },
+        models: {
+            auth: await AuthorizationModel.create(uid),
+            user: new UserModel(uid),
+            group: new GroupModel(uid),
+            message: new MessageModel(uid),
+            request: new RequestModel(uid)
+        }
+    };*/
+    let blah = {
+        request: req,
+        user: { uid: uid },
+        //models: null
+        models: {
+            auth: yield authorization_1.AuthorizationModel.create(uid),
+            user: null,
+            group: null,
+            message: null,
+            request: null,
+        }
+    };
+    console.log("finished constructing context");
+    return blah;
+});
+const server = new apollo_server_express_1.ApolloServer(Object.assign({}, schema_1.default, { context, playground: {
+        settings: {
+            "editor.theme": "dark",
+            "editor.cursorShape": 'line'
+        }
+    } }));
+// path defaults to '/graphql'
+//server.applyMiddleware({ app, cors: corsOptions }); <-- TODO: is this necessary?
+server.applyMiddleware({ app });
+/**
+ * @desc Servir l'interface admin du backend ("adminview")
+ * =======================================================
+ * On redirige vers la "mini-application" adminview.
+ * Il s'agit en fait d'un express.Router, qui sert a creer un "sous-middleware stack".
+ * Par cette interface admin, on a accès :
+ * - à une API REST fait-maison (peut-être encore à débugger)
+ * - à GraphQL Voyager, un package qui permet d'afficher une représentation sous forme de graphe du schéma GraphQL.
+ */
+// servir les fichiers statiques (e.g. images) rendant l'interface jolie
+app.use('/assets', express_1.default.static(path_1.default.resolve(__dirname, '../', 'assets')));
+// setup the 'pug' view engine. the adminview "sub-app" will inherit this. https://expressjs.com/en/4x/api.html#app.set
+//console.log("Express app is running at (__dirname) ", __dirname);
+//console.log("Express app is running at (full path) ", path.resolve(__dirname));let viewpath = path.resolve(__dirname, 'adminview', 'views');
+let viewpath = path_1.default.resolve(__dirname, 'adminview', 'views');
+app.set('views', viewpath);
+app.set('view engine', 'pug');
+app.use('/adminview', admin_router_1.default); // catches and resolves HTTP requests to paths '/adminview/*'
+// also redirect other HTTP GET requests to the adminview router
+app.get('/', function (req, res) {
+    res.redirect('/adminview');
+});
+/**
+ * @desc Catch-all
+ * ===============
+ * Normalement aucune requête ne devrait arriver au dernier middleware :
+ * les requêtes GraphQL doivent être adressées à /graphql,
+ * les requêtes de connexion du frontend doivent être adressées à /login,
+ * les requêtes vers l'adminview doivent être adressées à /adminview/*
+ * Donc c'est qu'il y a un problème quelque part. On le log et on répond 500 Internal Server Error (ou 400 Bad Request?).
+ *
+ * @todo faire un loggage plus propre que ça...
+ */
+app.use('/', (req, res) => {
+    console.log("Erreur: une requête est arrivée au dernier middleware");
+    res.status(500).send({ error: "unexpectedly triggered catchall" });
+});
+exports.default = app;
+//# sourceMappingURL=app.js.map
\ No newline at end of file
diff --git a/tsbuild/src/app.js.map b/tsbuild/src/app.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..3891e2c71918dd87d7944f412ee660eb66fbae66
--- /dev/null
+++ b/tsbuild/src/app.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/authorization.js b/tsbuild/src/graphql/models/authorization.js
new file mode 100644
index 0000000000000000000000000000000000000000..24eabf57a1aa0516514409c9e7ec5f9ba2fbb60d
--- /dev/null
+++ b/tsbuild/src/graphql/models/authorization.js
@@ -0,0 +1,272 @@
+"use strict";
+/**
+ * @file Fonctions qui gerent l'autorisation des utilisateurs
+ * @author ofacklam
+ * @memberof GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const tools_1 = require("./tools");
+const user_1 = require("../../ldap/export/user");
+/*
+ * There are 7 levels of authorization
+ *  none : doesn't know the group / the user exists
+ *  connectedOrOnplatal : knows the group exists, can use TOL
+ *  viewer : can see the group
+ *  member : part of the group
+ *  speaker : allowed to speak for the group
+ *  admin : admin of the group
+ *  supervisor : allowed to take control of the group
+ */
+class AuthorizationModel {
+    /**
+     * @memberof GraphQL
+     * @class AuthorizationModel
+     * @summary Autorisation des utilisateurs.
+     * @classdesc Cette classe contient les méthodes d'autorisation de l'utilisateur dans le 'context'.
+     * @arg {string} uid - L'identifiant de l'utilisateur.
+     */
+    constructor(uid) {
+        this.uid = uid;
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui crée une nouvelle instance de AuthorizationModel et charge les données
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @returns {Promise(AuthorizationModel)} Renvoie un nouveau AuthorizationModel avec cet utilisateur
+     * @async
+     * @static
+     */
+    static create(uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let model = new AuthorizationModel(uid);
+            console.log("constructing AuthorizationModel...");
+            if (model.isAuthenticated()) {
+                console.log("model is authenticated. fetching data...");
+                yield model.fetchData();
+            }
+            console.log("finished constructing AuthorizationModel");
+            return model;
+        });
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function fetchData
+     * @summary Fonction qui recupere toutes les données pour populer les champs a partir de l'uid.
+     * @async
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            console.log("calling UT.peek from ldap connector (User Tool)...");
+            let data = yield user_1.User.peek(this.uid);
+            console.log("UT.peek returned with data:");
+            console.log(data);
+            this.viewerOf = yield tools_1.Tools.viewerOf(data);
+            this.memberOf = yield tools_1.Tools.memberOf(data);
+            this.speakerOf = yield tools_1.Tools.viewerOf(data);
+            this.adminOf = yield tools_1.Tools.adminOf(data);
+            this.supervisorOf = yield tools_1.Tools.supervisorOf(data);
+        });
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function getUid
+     * @summary Fonction qui renvoit l'identifiant de l'utilisateur
+     * @return {string} Renvoie l'uid de l'utilisateur du 'context'
+     */
+    getUid() {
+        return this.uid;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isConnectedOrOnplatal
+     * @summary Fonction qui renvoit si l'utilisateur est connecté ou on-platal
+     * @return {boolean} Renvoie true si l'utilisateur est connecté ou on-platal
+     */
+    isConnectedOrOnplatal() {
+        return (this.uid != AuthorizationModel.PUBLICUSER);
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isAuthenticated
+     * @summary Fonction qui renvoit si l'utilisateur est authentifié
+     * @return {boolean} Renvoie true si l'utilisateur est authentifié
+     */
+    isAuthenticated() {
+        console.log("running model.isAuthenticated...");
+        return (this.uid != AuthorizationModel.PUBLICUSER && this.uid != AuthorizationModel.ONPLATALUSER);
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isViewer
+     * @summary Fonction qui renvoit si l'utilisateur est viewer du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {boolean} Renvoie true si l'utilisateur est viewer du groupe.
+     */
+    isViewer(gid) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let groups = this.viewerOf;
+            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function groupsViewer
+     * @summary Fonction qui renvoit les groupes dont l'utilisateur est viewer.
+     * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est viewer.
+     */
+    groupsViewer() {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            return this.viewerOf;
+        }
+        return null;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isMember
+     * @summary Fonction qui renvoit si l'utilisateur est membre du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {boolean} Renvoie true si l'utilisateur est membre du groupe.
+     */
+    isMember(gid) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let groups = this.memberOf;
+            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isMemberOr
+     * @summary Fonction qui renvoit si l'utilisateur est membre d'au moins un de ces groupes.
+     * @arg {GroupSet} groups - Ensemble de groupes.
+     * @return {boolean} Renvoie true si l'utilisateur est membre d'un des groupes
+     */
+    isMemberOr(groups) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let member = this.memberOf;
+            for (let gid of groups) {
+                if (member.simpleGroups.has(gid) || member.metaGroups.has(gid)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function groupsMember
+     * @summary Fonction qui renvoit les groupes dont l'utilisateur est member.
+     * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est member.
+     */
+    groupsMember() {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            return this.memberOf;
+        }
+        return null;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isSpeaker
+     * @summary Fonction qui renvoit si l'utilisateur est speaker du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {boolean} Renvoie true si l'utilisateur est speaker du groupe.
+     */
+    isSpeaker(gid) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let groups = this.speakerOf;
+            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function groupsSpeaker
+     * @summary Fonction qui renvoit les groupes dont l'utilisateur est speaker.
+     * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est speaker.
+     */
+    groupsSpeaker() {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            return this.speakerOf;
+        }
+        return null;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isAdmin
+     * @summary Fonction qui renvoit si l'utilisateur est admin du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {boolean} Renvoie true si l'utilisateur est admin du groupe.
+     */
+    isAdmin(gid) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let groups = this.adminOf;
+            let is_admin = groups.simpleGroups.has(gid) || groups.metaGroups.has(gid);
+            //TODO : Vérifier s'il a pris les droits d'admin en étant supervisor
+            let took_admin_rights = false;
+            return (is_admin || took_admin_rights);
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function groupsAdmin
+     * @summary Fonction qui renvoit les groupes dont l'utilisateur est admin.
+     * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est admin.
+     */
+    groupsAdmin() {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            return this.adminOf;
+        }
+        return null;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function isSupervisor
+     * @summary Fonction qui renvoit si l'utilisateur est supervisor du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {boolean} Renvoie true si l'utilisateur est supervisor du groupe.
+     */
+    isSupervisor(gid) {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            let groups = this.supervisorOf;
+            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
+        }
+        return false;
+    }
+    /**
+     * @memberof GraphQL.AuthorizationModel#
+     * @function groupsSupervisor
+     * @summary Fonction qui renvoit les groupes dont l'utilisateur est supervisor.
+     * @return {GroupCollection} Renvoie la collection de groupes dont l'utilisateur est supervisor.
+     */
+    groupsSupervisor() {
+        //ensure uid is valid !!!!!!!!
+        if (this.isAuthenticated()) {
+            return this.supervisorOf;
+        }
+        return null;
+    }
+}
+AuthorizationModel.PUBLICUSER = "public_user";
+AuthorizationModel.ONPLATALUSER = "public_onplatal_user";
+exports.AuthorizationModel = AuthorizationModel;
+//# sourceMappingURL=authorization.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/authorization.js.map b/tsbuild/src/graphql/models/authorization.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..450781046b146c6e22a7f464ea29da28274f2dc9
--- /dev/null
+++ b/tsbuild/src/graphql/models/authorization.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../../src/graphql/models/authorization.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/groupModel.js b/tsbuild/src/graphql/models/groupModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..a36bcb26603d1f48c69962d2cb695bf1f00a57d5
--- /dev/null
+++ b/tsbuild/src/graphql/models/groupModel.js
@@ -0,0 +1,423 @@
+"use strict";
+/**
+ * @file Fonctions qui implémentent les requetes relatives aux groupes
+ * @author ofacklam
+ * @memberof GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const groups_1 = require("../object_resolvers/groups");
+const knex_router_1 = __importDefault(require("../../../db/knex_router"));
+const tools_1 = require("./tools");
+class GroupModel {
+    /**
+     * @memberof GraphQL
+     * @class GroupModel
+     * @summary Requetes relatives aux groupes.
+     * @classdesc Cette classe contient les méthodes implémentant les requetes relatives aux groupes.
+     * @arg {string} contextUser - L'identifiant de l'utilisateur du 'context'
+     */
+    constructor(contextUser) {
+        this.contextUser = contextUser;
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getGroup
+     * @summary Fonction qui renvoie un groupe donné.
+     * @arg {string} gid - Identifiant demandé.
+     * @return {Promise(Group)} Renvoie le groupe dont l'identifiant est 'gid'
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    getGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let data = yield knex_router_1.default.select('type').from('groups').where('gid', gid);
+            if (data.length > 0) {
+                let type = data[0].type;
+                switch (type) {
+                    case 'simple':
+                        return new groups_1.SimpleGroup(gid);
+                    case 'meta':
+                        return new groups_1.MetaGroup(gid);
+                    default:
+                        return null;
+                }
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getSimpleGroup
+     * @summary Fonction qui renvoie un groupe simple donné.
+     * @arg {string} gid - Identifiant demandé.
+     * @return {Promise(SimpleGroup)} Renvoie le groupe dont l'identifiant est 'gid'
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    getSimpleGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return groups_1.SimpleGroup.tryCreate(gid);
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getMetaGroup
+     * @summary Fonction qui renvoie un méta-groupe donné.
+     * @arg {string} gid - Identifiant demandé.
+     * @return {Promise(MetaGroup)} Renvoie le groupe dont l'identifiant est 'gid'
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    getMetaGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return groups_1.MetaGroup.tryCreate(gid);
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getAllGroupsByCollection
+     * @summary Fonction qui renvoie tous les groupes donnés en argument.
+     * @arg {GroupCollection} groups - Collection d'identifiants, supposés valides.
+     * @return {Group[]} Renvoie le tableau de groupes correspondant
+     * @rights connectedOrOnplatal
+     */
+    getAllGroupsByCollection(groups) {
+        let res;
+        for (let s of groups.simpleGroups) {
+            res.push(new groups_1.SimpleGroup(s));
+        }
+        for (let m of groups.metaGroups) {
+            res.push(new groups_1.MetaGroup(m));
+        }
+        return res;
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getAllGroupsBySet
+     * @summary Fonction qui renvoie tous les groupes donnés en argument.
+     * @arg {GroupSet} groups - Ensemble d'identifiants, supposés valides.
+     * @return {Promise(Group[])} Renvoie le tableau de groupes correspondant
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    getAllGroupsBySet(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let res;
+            for (let g of groups) {
+                res.push(yield this.getGroup(g));
+            }
+            return res;
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getAllSimpleGroups
+     * @summary Fonction qui renvoie tous les groupes simples donnés en argument.
+     * @arg {GroupSet} groups - Ensemble d'identifiants, supposés valides.
+     * @return {SimpleGroup[]} Renvoie le tableau de groupes correspondant
+     * @rights connectedOrOnplatal
+     */
+    getAllSimpleGroups(groups) {
+        let res;
+        for (let g of groups) {
+            res.push(new groups_1.SimpleGroup(g));
+        }
+        return res;
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function likeGroup
+     * @summary Fonction pour devenir sympathisant
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights viewer du groupe
+     */
+    likeGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // Pour l'instant, ce n'est pas a implémenter...
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function unlikeGroup
+     * @summary Fonction pour devenir non-sympathisant
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights viewer du groupe
+     */
+    unlikeGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // Pour l'instant, ce n'est pas a implémenter...
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function userLeaveGroup
+     * @summary Fonction pour quitter un groupe
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights member du groupe
+     */
+    userLeaveGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function writePostsSummary
+     * @summary Fonction pour écrire le résumé des posts.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} content - Contenu du résumé.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights speaker du groupe
+     */
+    writePostsSummary(gid, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function createSubgroup
+     * @summary Fonction pour créer un sous-groupe
+     * @arg {createSubgroupArgs} args - Les arguments pour la création.
+     * @return {Promise(Group)} Renvoie le groupe créé.
+     * @async
+     * @rights admin du groupe
+     */
+    createSubgroup(args) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            //TODO : Vérifier que 'parent' est un groupe _simple_.
+            // TODO : finish
+            /*if (typeof args.fromGroup != 'string')
+                throw "Illegal argument : parent_uid must be a non null string";
+            if (typeof args.subName != 'string')
+                throw "Illegal argument : name must be a non null string";
+    
+            let rasGID = await getAvailableGID(args.subGid);
+    
+            // TODO : appeller une fonction de LDAPUser pour y créer un groupe.
+            await knex('simple_groups').insert({
+                uid: rasGID,
+                parent_uid: args.parent_uid,
+                createdAt: knex.fn.now(),
+                updatedAt: this.createdAt,
+                name: args.name,
+                website: args.website,
+                description: args.description,
+                school: args.school,
+                type: "simple"
+            });
+    
+            return getGroup(rasGID);*/
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function getAvailableGID
+     * @summary Attribue un GID qui n'a pas encore été utilisé à un groupe
+     * @desc Escape le string initialGID si necessaire (ramené à de l'ASCII sans espace), puis si le gid est deja pris rajoute un n a la fin et reteste
+     * @arg {string} initialGID - Le gid initial du groupe, qu'il faut tester pour l'unicité.
+     * @return {Promise(string)} Renvoie le gid unique pour ce groupe.
+     * @rights authentified
+     * remarque : n'importe qui peut tester si un groupe existe en demandant a créer un groupe avec ce nom la et en regardant si
+     * son GID a été modifié. Je ne vois pas comment contourner ce problème, c'est donc une faille permanente (mineure) de sigma.
+     * // ofacklam -> savoir qu'un groupe existe est autorisé pour toute personne connectée ou on-platal et il faut etre connecté pour
+     * // utiliser cette fonction-ci donc il n'y a pas de probleme.
+     */
+    getAvailableGID(initialGID) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let rasGID = tools_1.Tools.escapeID(initialGID);
+            const res = knex_router_1.default.from('groups').where('gid', rasGID);
+            if (res.length == 0) {
+                return (rasGID);
+            }
+            else {
+                return (this.getAvailableGID(rasGID + 'n'));
+            }
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function makeAdmin
+     * @summary Fonction pour rendre un membre admin
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @return {Promise(User)} Renvoie l'utilisateur promu.
+     * @async
+     * @rights admin du groupe
+     */
+    makeAdmin(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : vérifier que l'utilisateur est bien déja membre !!
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function unmakeAdmin
+     * @summary Fonction pour rendre un membre non-admin
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @return {Promise(User)} Renvoie l'utilisateur dé-promu.
+     * @async
+     * @rights admin du groupe
+     */
+    unmakeAdmin(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : vérifier que l'utilisateur est bien déja membre !!
+            //TODO : relacher les droits admin (des groupes enfants) pris en étant admin.
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function makeSpeaker
+     * @summary Fonction pour rendre un membre speaker
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @return {Promise(User)} Renvoie l'utilisateur promu.
+     * @async
+     * @rights admin du groupe
+     */
+    makeSpeaker(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : vérifier que l'utilisateur est bien déja membre !!
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function unmakeSpeaker
+     * @summary Fonction pour rendre un membre non-speaker
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @return {Promise(User)} Renvoie l'utilisateur dé-promu.
+     * @async
+     * @rights admin du groupe
+     */
+    unmakeSpeaker(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : vérifier que l'utilisateur est bien déja membre !!
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function editGroup
+     * @summary Fonction pour modifier un groupe.
+     * @arg {editGroupArgs} args - Les arguments de la modification.
+     * @return {Promise(Group)} Renvoie le groupe modifié.
+     * @async
+     * @rights admin du groupe
+     */
+    editGroup(args) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function addVisibilityEdge
+     * @summary Fonction pour ajouter une arete de visibilité.
+     * @arg {string} forGroup - Le groupe a rendre visible.
+     * @arg {string} visibleBy - Le groupe qui pourra voir.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe 'forGroup'
+     */
+    addVisibilityEdge(forGroup, visibleBy) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function removeVisibilityEdge
+     * @summary Fonction pour retirer une arete de visibilité.
+     * @arg {string} forGroup - Le groupe a rendre invisible.
+     * @arg {string} visibleBy - Le groupe qui ne pourra plus voir.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe 'forGroup'
+     */
+    removeVisibilityEdge(forGroup, visibleBy) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function removeUser
+     * @summary Fonction pour enlever un membre du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @return {Promise(User)} Renvoie l'utilisateur.
+     * @async
+     * @rights admin du groupe
+     */
+    removeUser(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function takeAdminRights
+     * @summary Fonction pour prendre les droits admin du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur qui prend les droits.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights supervisor du groupe
+     */
+    takeAdminRights(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*await knex('taken_rights').insert({
+                user_uid: user.uid,
+                group_uid: groupUID,
+                justification: justification
+            });
+            return true;*/
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupModel#
+     * @function releaseAdminRights
+     * @summary Fonction pour relacher les droits admin du groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} uid - Identifiant de l'utilisateur qui relache les droits.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights supervisor du groupe
+     */
+    releaseAdminRights(gid, uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : relacher récursivement
+            throw "Not implemented";
+            /*return knex('taken_rights').del().where('user_uid', user.uid).where('group_uid', groupUID);*/
+        });
+    }
+}
+exports.GroupModel = GroupModel;
+//# sourceMappingURL=groupModel.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/groupModel.js.map b/tsbuild/src/graphql/models/groupModel.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..6084fb50155ac8051fc36f3fec8cc0167663b0da
--- /dev/null
+++ b/tsbuild/src/graphql/models/groupModel.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"groupModel.js","sourceRoot":"","sources":["../../../../src/graphql/models/groupModel.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/messageModel.js b/tsbuild/src/graphql/models/messageModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..711794871a44273572c4a426c336179b12dcc0b2
--- /dev/null
+++ b/tsbuild/src/graphql/models/messageModel.js
@@ -0,0 +1,546 @@
+"use strict";
+/**
+ * @file Fonctions qui implémentent les requetes relatives aux messages
+ * @author ofacklam
+ * @memberof GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const messages_1 = require("../object_resolvers/messages");
+class MessageModel {
+    /**
+     * @memberof GraphQL
+     * @class MessageModel
+     * @summary Requetes relatives aux messages.
+     * @classdesc Cette classe contient les méthodes implémentant les requetes relatives aux messages.
+     * @arg {string} contextUser - L'identifiant de l'utilisateur du 'context'
+     */
+    constructor(contextUser) {
+        this.contextUser = contextUser;
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAnnouncement
+     * @summary Fonction qui renvoie une annonce donnée.
+     * @arg {number} mid - Identifiant demandé.
+     * @return {Promise(Announcement)} Renvoie l'annonce dont l'identifiant est 'mid'
+     * @async
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    getAnnouncement(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return messages_1.Announcement.tryCreate(mid);
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getEvent
+     * @summary Fonction qui renvoie un evenement donné.
+     * @arg {number} mid - Identifiant demandé.
+     * @return {Promise(Event)} Renvoie l'évenement dont l'identifiant est 'mid'
+     * @async
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    getEvent(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return messages_1.Event.tryCreate(mid);
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getPrivatePost
+     * @summary Fonction qui renvoie un post privé donné.
+     * @arg {number} mid - Identifiant demandé.
+     * @return {Promise(PrivatePost)} Renvoie le post privé dont l'identifiant est 'mid'
+     * @async
+     * @rights membre du groupe recipient
+     */
+    getPrivatePost(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return messages_1.PrivatePost.tryCreate(mid);
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getQuestion
+     * @summary Fonction qui renvoie une question donnée.
+     * @arg {number} mid - Identifiant demandé.
+     * @return {Promise(Question)} Renvoie la question dont l'identifiant est 'mid'
+     * @async
+     * @rights viewer du groupe recipient
+     */
+    getQuestion(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return messages_1.Question.tryCreate(mid);
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAnswer
+     * @summary Fonction qui renvoie une réponse donnée.
+     * @arg {number} mid - Identifiant demandé.
+     * @return {Promise(Answer)} Renvoie la réponse dont l'identifiant est 'mid'
+     * @async
+     * @rights viewer du groupe author
+     */
+    getAnswer(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return messages_1.Answer.tryCreate(mid);
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAllMessages
+     * @summary Fonction qui renvoie tous les messages visibles.
+     * @arg {GroupCollection} groups - Un ensemble d'identifiants, supposés valides.
+     * @return {Promise(Message[])} Renvoie tous les messages émis ou reçus par ces groupes
+     * @async
+     * @rights member of groups
+     */
+    getAllMessages(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAllAnnouncements
+     * @summary Fonction qui renvoie toutes les annonces visibles.
+     * @arg {GroupCollection} groups - Un ensemble d'identifiants, supposés valides.
+     * @return {Promise(Announcement[])} Renvoie toutes les annonces émises ou reçues par ces groupes
+     * @async
+     * @rights member of groups
+     */
+    getAllAnnouncements(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*let result = await knex.select().from('announcements').whereIn('id', selection);
+            result = result.concat(
+                await knex.select().from('events').whereIn('id', selection)
+            );
+            for (let r of result) {
+                r.type = 'Announcement';
+            }
+            return result;*/
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAllEvents
+     * @summary Fonction qui renvoie tous les évenements visibles.
+     * @arg {GroupCollection} groups - Un ensemble d'identifiants, supposés valides.
+     * @return {Promise(Event[])} Renvoie tous les évenements émis ou reçus par ces groupes
+     * @async
+     * @rights member of groups
+     */
+    getAllEvents(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*let result = await knex.select().from('events').whereIn('id', selection);
+            for (let r of result) {
+                r.type = 'Announcement';
+            }
+            return result;*/
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function getAllPrivatePosts
+     * @summary Fonction qui renvoie tous les posts privés visibles.
+     * @arg {GroupCollection} groups - Un ensemble d'identifiants, supposés valides.
+     * @return {Promise(PrivatePost[])} Renvoie tous les posts privés de ces groupes
+     * @async
+     * @rights member of groups
+     */
+    getAllPrivatePosts(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            // let result = await knex('private_posts').select().whereIn('id', received_messages);
+            // for(let entry of result){
+            //     entry.type = "PrivatePost";
+            // }
+            // return result;
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function userParticipate
+     * @summary Fonction pour participer a un evenement.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @arg {number} mid - Identifiant de l'évenement.
+     * @return {Promise(boolean)} Renvoie true si modification réussie
+     * @async
+     * @rights member d'un groupe author ou recipient
+     */
+    userParticipate(uid, mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function userUnparticipate
+     * @summary Fonction pour ne plus participer a un evenement.
+     * @arg {string} uid - Identifiant de l'utilisateur.
+     * @arg {number} mid - Identifiant de l'évenement.
+     * @return {Promise(boolean)} Renvoie true si modification réussie
+     * @async
+     * @rights member d'un groupe author ou recipient
+     */
+    userUnparticipate(uid, mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function groupParticipate
+     * @summary Fonction pour participer a un evenement.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {number} forEvent - Identifiant de l'évenement.
+     * @return {Promise(boolean)} Renvoie true si modification réussie
+     * @async
+     * @rights member d'un groupe author ou recipient
+     */
+    groupParticipate(gid, forEvent) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function groupUnparticipate
+     * @summary Fonction pour ne plus participer a un evenement.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {number} forEvent - Identifiant de l'évenement.
+     * @return {Promise(boolean)} Renvoie true si modification réussie
+     * @async
+     * @rights member d'un groupe author ou recipient
+     */
+    groupUnparticipate(gid, forEvent) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function createQuestion
+     * @summary Fonction pour créer une question.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(Question)} Renvoie la question créée.
+     * @async
+     * @rights viewer du groupe
+     */
+    createQuestion(gid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function editQuestion
+     * @summary Fonction pour modifier une question.
+     * @arg {number} mid - Identifiant de la question.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(Question)} Renvoie la question modifiée.
+     * @async
+     * @rights viewer du groupe et author de la question
+     */
+    editQuestion(mid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function removeQuestion
+     * @summary Fonction pour supprimer une question.
+     * @arg {number} mid - Identifiant de la question.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights viewer du groupe et author de la question
+     */
+    removeQuestion(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function createPrivatePost
+     * @summary Fonction pour créer un post privé.
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(PrivatePost)} Renvoie le post créé.
+     * @async
+     * @rights member du groupe
+     */
+    createPrivatePost(gid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function editPrivatePost
+     * @summary Fonction pour modifier un post privé.
+     * @arg {number} mid - Identifiant du post.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(PrivatePost)} Renvoie le post modifié.
+     * @async
+     * @rights member du groupe et author du post
+     */
+    editPrivatePost(mid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function removePrivatePost
+     * @summary Fonction pour supprimer un post privé.
+     * @arg {number} mid - Identifiant du post.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights member du groupe et author du post
+     */
+    removePrivatePost(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function createAnnouncement
+     * @summary Fonction pour créer une annonce.
+     * @arg {string} from_gid - Identifiant du groupe émetteur.
+     * @arg {GroupSet} to_groups - Les groupes destinataires.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @arg {number} event_mid - Identifiant de l'évenement.
+     * @return {Promise(Announcement)} Renvoie l'annonce créée.
+     * @async
+     * @rights speaker du groupe émetteur
+     */
+    createAnnouncement(from_gid, to_groups, title, content, event_mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function editAnnouncement
+     * @summary Fonction pour modifier une annonce.
+     * @arg {number} mid - Identifiant de l'annonce.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @arg {number} event_mid - Identifiant de l'évenement.
+     * @return {Promise(Announcement)} Renvoie l'annonce modifiée.
+     * @async
+     * @rights speaker du groupe émetteur
+     */
+    editAnnouncement(mid, title, content, event_mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function removeAnnouncement
+     * @summary Fonction pour supprimer une annonce.
+     * @arg {number} mid - Identifiant de l'annonce.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights speaker du groupe
+     */
+    removeAnnouncement(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function createEvent
+     * @summary Fonction pour créer un évenement.
+     * @arg {string} from_gid - Identifiant du groupe émetteur.
+     * @arg {GroupSet} to_groups - Les groupes destinataires.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @arg {string} location - Lieu.
+     * @arg {string} startTime - Date de début.
+     * @arg {string} endTime - Date de fin.
+     * @arg {number} announcement_mid - Identifiant de l'annonce.
+     * @return {Promise(Event)} Renvoie l'évenement créé.
+     * @async
+     * @rights speaker du groupe émetteur
+     */
+    createEvent(from_gid, to_groups, title, content, location, startTime, endTime, announcement_mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function editEvent
+     * @summary Fonction pour modifier un evenement.
+     * @arg {number} mid - Identifiant de l'évenement.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @arg {string} location - Lieu.
+     * @arg {string} startTime - Date de début.
+     * @arg {string} endTime - Date de fin.
+     * @arg {number} announcement_mid - Identifiant de l'annonce.
+     * @return {Promise(Event)} Renvoie l'evenement modifié.
+     * @async
+     * @rights speaker du groupe émetteur
+     */
+    editEvent(mid, title, content, location, startTime, endTime, announcement_mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function removeEvent
+     * @summary Fonction pour supprimer un évenement.
+     * @arg {number} mid - Identifiant de l'évenement.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights speaker du groupe
+     */
+    removeEvent(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function createAnswer
+     * @summary Fonction pour créer une réponse.
+     * @arg {number} mid - Identifiant de la question.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(Answer)} Renvoie la réponse créée.
+     * @async
+     * @rights speaker du groupe
+     */
+    createAnswer(mid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function editAnswer
+     * @summary Fonction pour modifier une réponse.
+     * @arg {number} mid - Identifiant de la réponse.
+     * @arg {string} title - Titre.
+     * @arg {string} content - Contenu.
+     * @return {Promise(Answer)} Renvoie la réponse modifiée.
+     * @async
+     * @rights speaker du groupe
+     */
+    editAnswer(mid, title, content) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function removeAnswer
+     * @summary Fonction pour supprimer une réponse.
+     * @arg {number} mid - Identifiant de la réponse.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights speaker du groupe
+     */
+    removeAnswer(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function censorQuestion
+     * @summary Fonction pour censurer une question.
+     * @arg {number} mid - Identifiant du message.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights admin du groupe
+     */
+    censorQuestion(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function censorAnswer
+     * @summary Fonction pour censurer une réponse.
+     * @arg {number} mid - Identifiant du message.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights admin du groupe
+     */
+    censorAnswer(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function censorPrivatePost
+     * @summary Fonction pour censurer un post privé.
+     * @arg {number} mid - Identifiant du message.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights admin du groupe
+     */
+    censorPrivatePost(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function censorAnnouncement
+     * @summary Fonction pour censurer une annonce.
+     * @arg {number} mid - Identifiant du message.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights admin du groupe ???? (lequel ??? -> le groupe author?)
+     */
+    censorAnnouncement(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.MessageModel#
+     * @function censorEvent
+     * @summary Fonction pour censurer un évenement.
+     * @arg {number} mid - Identifiant du message.
+     * @return {Promise(boolean)} Renvoie true si suppression réussie.
+     * @async
+     * @rights admin du groupe ???? (lequel ??? -> le groupe author?)
+     */
+    censorEvent(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+}
+exports.MessageModel = MessageModel;
+//# sourceMappingURL=messageModel.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/messageModel.js.map b/tsbuild/src/graphql/models/messageModel.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..2843f14ab70957f0b0f0807d751431713d076502
--- /dev/null
+++ b/tsbuild/src/graphql/models/messageModel.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"messageModel.js","sourceRoot":"","sources":["../../../../src/graphql/models/messageModel.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;AAEH,2DAA2G;AAI3G,MAAa,YAAY;IAErB;;;;;;OAMG;IACH,YAAY,WAAmB;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACnC,CAAC;IAID;;;;;;;;OAQG;IACG,eAAe,CAAC,GAAW;;YAC7B,OAAO,uBAAY,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,QAAQ,CAAC,GAAW;;YACtB,OAAO,gBAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,cAAc,CAAC,GAAW;;YAC5B,OAAO,sBAAW,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,GAAW;;YACzB,OAAO,mBAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,SAAS,CAAC,GAAW;;YACvB,OAAO,iBAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,cAAc,CAAC,MAAuB;;YACxC,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,mBAAmB,CAAC,MAAuB;;YAC7C,MAAM,iBAAiB,CAAC;YAExB;;;;;;;4BAOgB;QACpB,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,YAAY,CAAC,MAAuB;;YACtC,MAAM,iBAAiB,CAAC;YAExB;;;;4BAIgB;QACpB,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,kBAAkB,CAAC,MAAuB;;YAC5C,MAAM,iBAAiB,CAAC;YAExB,sFAAsF;YACtF,4BAA4B;YAC5B,kCAAkC;YAClC,IAAI;YACJ,iBAAiB;QACrB,CAAC;KAAA;IAED;;;;;;;;;OASG;IACG,eAAe,CAAC,GAAW,EAAE,GAAW;;YAC1C,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;OASG;IACG,iBAAiB,CAAC,GAAW,EAAE,GAAW;;YAC5C,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;OASG;IACG,gBAAgB,CAAC,GAAW,EAAE,QAAgB;;YAChD,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;OASG;IACG,kBAAkB,CAAC,GAAW,EAAE,QAAgB;;YAClD,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,cAAc,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YAC5D,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,YAAY,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YAC1D,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,cAAc,CAAC,GAAW;;YAC5B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,iBAAiB,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YAC/D,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,eAAe,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YAC7D,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,iBAAiB,CAAC,GAAW;;YAC/B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;;;OAYG;IACG,kBAAkB,CAAC,QAAgB,EAAE,SAAmB,EAAE,KAAa,EAAE,OAAe,EAAE,SAAiB;;YAC7G,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe,EAAE,SAAiB;;YACjF,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,kBAAkB,CAAC,GAAW;;YAChC,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;;;;;;OAeG;IACG,WAAW,CAAC,QAAgB,EAAE,SAAmB,EAAE,KAAa,EAAE,OAAe,EAAE,QAAgB,EAAE,SAAiB,EAAE,OAAe,EAAE,gBAAwB;;YACnK,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;;;;;OAcG;IACG,SAAS,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe,EAAE,QAAgB,EAAE,SAAiB,EAAE,OAAe,EAAE,gBAAwB;;YACvI,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,GAAW;;YACzB,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,YAAY,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YAC1D,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACG,UAAU,CAAC,GAAW,EAAE,KAAa,EAAE,OAAe;;YACxD,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,YAAY,CAAC,GAAW;;YAC1B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,cAAc,CAAC,GAAW;;YAC5B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,YAAY,CAAC,GAAW;;YAC1B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,iBAAiB,CAAC,GAAW;;YAC/B,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,kBAAkB,CAAC,GAAW;;YAChC,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,GAAW;;YACzB,MAAM,iBAAiB,CAAC;QAC5B,CAAC;KAAA;CAEJ;AArfD,oCAqfC"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/requestModel.js b/tsbuild/src/graphql/models/requestModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..cdd0b0bb1f3ae4c9fb827f9bc4ad25418b30e875
--- /dev/null
+++ b/tsbuild/src/graphql/models/requestModel.js
@@ -0,0 +1,313 @@
+"use strict";
+/**
+ * @file Fonctions qui implémentent les requetes relatives aux requetes
+ * @author ofacklam
+ * @memberof GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const requests_1 = require("../object_resolvers/requests");
+class RequestModel {
+    /**
+     * @memberof GraphQL
+     * @class RequestModel
+     * @summary Requetes relatives aux requetes.
+     * @classdesc Cette classe contient les méthodes implémentant les requetes relatives aux requetes.
+     * @arg {string} contextUser - L'identifiant de l'utilisateur du 'context'
+     */
+    constructor(contextUser) {
+        this.contextUser = contextUser;
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getUserJoinGroupRequest
+     * @summary Fonction qui renvoie une requete UserJoinGroup donnée.
+     * @arg {number} rid - Identifiant demandé.
+     * @return {Promise(UserJoinGroup)} Renvoie la requete dont l'identifiant est 'rid'
+     * @async
+     * @rights admin du groupe destinaire ou le user émetteur
+     */
+    getUserJoinGroupRequest(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return requests_1.UserJoinGroup.tryCreate(rid);
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getGroupJoinMetagroupRequest
+     * @summary Fonction qui renvoie une requete GroupJoinMetagroup donnée.
+     * @arg {number} rid - Identifiant demandé.
+     * @return {Promise(GroupJoinMetagroup)} Renvoie la requete dont l'identifiant est 'rid'
+     * @async
+     * @rights admin du groupe émetteur ou destinataire
+     */
+    getGroupJoinMetagroupRequest(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return requests_1.GroupJoinMetagroup.tryCreate(rid);
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getGroupCoauthorEventRequest
+     * @summary Fonction qui renvoie une requete GroupCoauthorEvent donnée.
+     * @arg {number} rid - Identifiant demandé.
+     * @return {Promise(GroupCoauthorEvent)} Renvoie la requete dont l'identifiant est 'rid'
+     * @async
+     * @rights admin du groupe émetteur ou destinataire
+     */
+    getGroupCoauthorEventRequest(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return requests_1.GroupCoauthorEvent.tryCreate(rid);
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getRequestsToGroup
+     * @summary Fonction qui renvoie toutes les requetes destinées a ce groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(Request[])} Renvoie la liste des requetes destinées a ce groupe.
+     * @async
+     * @rights admin du groupe
+     */
+    getRequestsToGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let r1 = yield this.getUserJoinGroupRequestsToGroup(gid);
+            let r2 = yield this.getGroupJoinMetagroupRequestsToGroup(gid);
+            let r3 = yield this.getGroupCoauthorEventRequestsToGroup(gid);
+            let r;
+            return r.concat(r1, r2, r3);
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getUserJoinGroupRequestsToGroup
+     * @summary Fonction qui renvoie toutes les requetes UserJoinGroup destinées a ce groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(UserJoinGroup[])} Renvoie la liste des requetes destinées a ce groupe.
+     * @async
+     * @rights admin du groupe
+     */
+    getUserJoinGroupRequestsToGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            // CODE A MODIFIER
+            /*let result = knex.select('id', 'useruid', 'message').from('user_join_group')
+                .where('recipient', recipient.gid);
+            return result.map(obj => {
+                obj.type = "UserJoinGroup";
+                return obj;
+            });*/
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getGroupJoinMetagroupRequestsToGroup
+     * @summary Fonction qui renvoie toutes les requetes GroupJoinMetagroup destinées a ce groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(GroupJoinMetagroup[])} Renvoie la liste des requetes destinées a ce groupe.
+     * @async
+     * @rights admin du groupe
+     */
+    getGroupJoinMetagroupRequestsToGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function getGroupCoauthorEventRequestsToGroup
+     * @summary Fonction qui renvoie toutes les requetes GroupCoauthorEvent destinées a ce groupe.
+     * @arg {string} gid - Identifiant du groupe.
+     * @return {Promise(GroupCoauthorEvent[])} Renvoie la liste des requetes destinées a ce groupe.
+     * @async
+     * @rights admin du groupe
+     */
+    getGroupCoauthorEventRequestsToGroup(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            //CODE A MODIFIER
+            /*let result = await knex.select('id', 'senderuid', 'eventuid', 'message').from('group_join_event')
+                .where('recipient', recipient.gid);
+            return result.map(obj => {
+                obj.type = "GroupJoinEvent";
+                return obj;
+            });*/
+            /*let result = await knex.select('id', 'senderuid', 'eventuid', 'message').from('your_group_host_event')
+                .where('recipient', recipient.gid);
+            return result.map(obj => {
+                obj.type = "YourGroupHostEvent";
+                return obj;
+            });*/
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function userRequestJoinGroup
+     * @summary Fonction pour demander a devenir membre
+     * @arg {string} gid - Identifiant du groupe.
+     * @arg {string} comment - Commentaire supplémentaire
+     * @return {Promise(UserJoinGroup)} Renvoie la requete créée.
+     * @async
+     * @rights viewer du groupe
+     */
+    userRequestJoinGroup(gid, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function groupRequestCoauthorEvent
+     * @summary Fonction pour demander a co-organiser un évenement
+     * @arg {string} from_gid - Identifiant du groupe émetteur.
+     * @arg {string} to_gid - Identifiant du groupe destinataire.
+     * @arg {number} event_mid - Identifiant de l'évenement considéré.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(GroupCoauthorEvent)} Renvoie la requete créée.
+     * @async
+     * @rights speaker du groupe émetteur
+     */
+    groupRequestCoauthorEvent(from_gid, to_gid, event_mid, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : Vérifier que l'évenement est bien organisé par le groupe destinataire (to_gid) !!! => sinon erreur
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function groupRequestJoinMetagroup
+     * @summary Fonction pour demander a rejoindre un méta-groupe
+     * @arg {string} from_gid - Identifiant du groupe émetteur.
+     * @arg {string} to_gid - Identifiant du méta-groupe destinataire.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(GroupJoinMetagroup)} Renvoie la requete créée.
+     * @async
+     * @rights admin du groupe émetteur
+     */
+    groupRequestJoinMetagroup(from_gid, to_gid, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function acceptUserJoinRequest
+     * @summary Fonction pour accepter une UserJoinGroup
+     * @arg {UserJoinGroup} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    acceptUserJoinRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function refuseUserJoinRequest
+     * @summary Fonction pour refuser une UserJoinGroup
+     * @arg {UserJoinGroup} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    refuseUserJoinRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function acceptGroupJoinRequest
+     * @summary Fonction pour accepter une GroupJoinMetagroup
+     * @arg {GroupJoinMetagroup} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    acceptGroupJoinRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function refuseGroupJoinRequest
+     * @summary Fonction pour refuser une GroupJoinMetagroup
+     * @arg {GroupJoinMetagroup} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    refuseGroupJoinRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function acceptGroupCoauthorEventRequest
+     * @summary Fonction pour accepter une GroupCoauthorEvent
+     * @arg {GroupCoauthorEvent} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    acceptGroupCoauthorEventRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+            /*let request = await knex('group_join_event').select().where('id', requestID);
+            if (!request.length)
+                return false;
+            
+            let group = request[0].senderuid;
+            let event = request[0].eventuid;
+            await knex('group_participation').insert({
+                group: group,
+                message: event,
+                status: "join"
+            });
+            await knex('group_join_event').where('id', requestID).del();
+            return;*/
+        });
+    }
+    /**
+     * @memberof GraphQL.RequestModel#
+     * @function refuseGroupCoauthorEventRequest
+     * @summary Fonction pour refuser une GroupCoauthorEvent
+     * @arg {GroupCoauthorEvent} req - L'objet requete.
+     * @arg {string} comment - Commentaire supplémentaire.
+     * @return {Promise(boolean)} Renvoie true si modification réussie.
+     * @async
+     * @rights admin du groupe destinataire
+     */
+    refuseGroupCoauthorEventRequest(req, comment) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //"comment" a envoyer par mail automatique
+            throw "Not implemented";
+            /*await knex('group_join_event').where('id', requestID).del();
+            //KNEX RENVOIE LE NOMBRE DE LIGNES AFFECTÉES -> il faut l'utiliser pour la valeur de retour
+            return true;*/
+        });
+    }
+}
+exports.RequestModel = RequestModel;
+//# sourceMappingURL=requestModel.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/requestModel.js.map b/tsbuild/src/graphql/models/requestModel.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..240ac950135fd37a5e1098356fa607c2b2292bb9
--- /dev/null
+++ b/tsbuild/src/graphql/models/requestModel.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"requestModel.js","sourceRoot":"","sources":["../../../../src/graphql/models/requestModel.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/tools.js b/tsbuild/src/graphql/models/tools.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b58780cf2801ffb79ddbaa3472a0a9802c31413
--- /dev/null
+++ b/tsbuild/src/graphql/models/tools.js
@@ -0,0 +1,254 @@
+"use strict";
+/**
+ * Namespace qui regroupe toutes les classes et toutes les fonctions qui permettent l'implémentation des resolvers du schéma GraphQL
+ * @namespace GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const knex_router_1 = __importDefault(require("../../../db/knex_router"));
+class GroupSet extends Set {
+    addList(l) {
+        for (let elt of l) {
+            this.add(elt);
+        }
+    }
+}
+exports.GroupSet = GroupSet;
+class Tools {
+    /**
+     * @memberof GraphQL
+     * @class Tools
+     * @summary Outils intermédiaires LDAP / BDD.
+     * @classdesc Cette classe contient des fonctions intermédiaires de recherche dans le LDAP / la BDD.
+     */
+    constructor() { }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui escape l'id donné en argument
+     * @arg {string} id - L'identifiant a escape.
+     * @return {Promise(Group)} Renvoie l'identifiant escapé.
+     * @static
+     */
+    static escapeID(id) {
+        return String(id).replace(' ', '_').replace(/\W/g, '').toLowerCase(); //the REGEXP matches all non-word characters (\W) in a global search (/../g)
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit l'union de deux ensembles
+     * @arg {GroupSet} A - Le premier ensemble.
+     * @arg {GroupSet} B - Le deuxieme ensemble.
+     * @return {Promise(GroupSet)} Renvoie un nouveau GroupSet contenant l'union de A et B.
+     * @static
+     */
+    static union(A, B) {
+        let union = new GroupSet(A);
+        for (let b of B) {
+            union.add(b);
+        }
+        return union;
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes simples dont le user est membre.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupSet)} Renvoie un GroupSet contenant le nom des groupes simples.
+     * @static
+     * @async
+     */
+    static memberOfSimple(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            return new GroupSet(data.members);
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes simples dont le user est speaker.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupSet)} Renvoie un GroupSet contenant le nom des groupes simples.
+     * @static
+     * @async
+     */
+    static speakerOfSimple(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let speaker = new GroupSet(data.speakers);
+            speaker.addList(data.admins);
+            return speaker;
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes simples dont le user est administrateur.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupSet)} Renvoie un GroupSet contenant le nom des groupes simples.
+     * @static
+     * @async
+     */
+    static adminOfSimple(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            return new GroupSet(data.admins);
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les méta-groupes dont ces groupes sont membres.
+     * @arg {GroupSet} groups - Un ensemble de gid des groupes a considérer.
+     * @return {Promise(GroupSet)} Renvoie un GroupSet contenant le nom des méta-groupes.
+     * @static
+     * @async
+     */
+    static metaGroupsOfGroups(groups) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let metas = yield knex_router_1.default.select('meta_group_gid').from('metagroup_memberships').whereIn('simple_group_gid', groups);
+            return new GroupSet(metas.map(elt => {
+                return elt.meta_group_gid;
+            }));
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes (simples ou méta) dont le user est membre.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
+     * @static
+     * @async
+     */
+    static memberOf(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let simple = yield Tools.memberOfSimple(data);
+            return { simpleGroups: simple, metaGroups: yield Tools.metaGroupsOfGroups(simple) };
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes (simples ou méta) dont le user est speaker.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
+     * @static
+     * @async
+     */
+    static speakerOf(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let speaker = yield Tools.speakerOfSimple(data);
+            let admin = yield Tools.adminOfSimple(data);
+            return { simpleGroups: speaker, metaGroups: yield Tools.metaGroupsOfGroups(admin) };
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoit tous les groupes (simples ou méta) dont le user est administrateur.
+     * @arg {userData} data - Données de l'utilisateur.
+     * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
+     * @static
+     * @async
+     */
+    static adminOf(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let simple = yield Tools.adminOfSimple(data);
+            return { simpleGroups: simple, metaGroups: yield Tools.metaGroupsOfGroups(simple) };
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui fait un parcours en profondeur de l'arbre de racine `gid` et renvoie la liste de tous les noeuds.
+     * @arg {string} gid - Identifiant du groupe, supposé valide.
+     * @return {Promise(string[])} Renvoie une liste contenant le nom des groupes dans cet arbre.
+     * @static
+     * @async
+     */
+    static DFS(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let res = [gid];
+            let children = yield knex_router_1.default.select('gid').from('groups').where('parent_gid', gid);
+            for (let child of children) {
+                let sub_tree = yield Tools.DFS(child.gid);
+                res = res.concat(sub_tree);
+            }
+            return res;
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui fait un parcours a profondeur 1 de l'arbre de racine `gid` et renvoie la liste des noeuds.
+     * @arg {string} gid - Identifiant du groupe, supposé valide.
+     * @return {Promise(string[])} Renvoie une liste contenant le nom des groupes a profondeur 1.
+     * @static
+     * @async
+     */
+    static oneDownSearch(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let res = [gid];
+            let children = yield knex_router_1.default.select('gid').from('groups').where('parent_gid', gid);
+            for (let child of children) {
+                res.push(child.gid);
+            }
+            return res;
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoie tous les groupes dont l'utilisateur est supervisor.
+     * @desc Utilise {@link Tools.oneDownSearch} pour avoir la profondeur 1 des arbres enracinés en chacun des groupes dont il est admin.
+     * @arg {userData} data - Données du user.
+     * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
+     * @static
+     * @async
+     */
+    static supervisorOf(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let groups = yield Tools.adminOf(data);
+            let simple = new GroupSet();
+            let meta = new GroupSet();
+            for (let g of groups.simpleGroups) {
+                simple.addList(yield Tools.oneDownSearch(g));
+            }
+            for (let g of groups.metaGroups) {
+                meta.addList(yield Tools.oneDownSearch(g));
+            }
+            return { simpleGroups: simple, metaGroups: meta };
+        });
+    }
+    /**
+     * @memberof GraphQL
+     * @summary Fonction qui renvoie tous les groupes dont l'utilisateur est viewer.
+     * @desc Utilise {@link Tools.oneDownSearch} pour avoir la profondeur 1 des arbres enracinés en chacun des groupes dont il est membre.
+     * @arg {userData} data - Données du user.
+     * @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
+     * @static
+     * @async
+     */
+    static viewerOf(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let groups = yield Tools.memberOf(data);
+            let simple = new GroupSet();
+            let meta = new GroupSet();
+            //Ajouter les groupes dont il est membre + les fils a profondeur 1
+            for (let g of groups.simpleGroups) {
+                simple.addList(yield Tools.oneDownSearch(g));
+            }
+            for (let g of groups.metaGroups) {
+                meta.addList(yield Tools.oneDownSearch(g));
+            }
+            //Ajouter les groupes simples qui sont dans ses métagroupes
+            let s = yield knex_router_1.default.select('simple_group_gid').from('metagroup_memberships').whereIn('meta_group_gid', groups.metaGroups);
+            simple.addList(s.map(elt => {
+                return elt.simple_group_gid;
+            }));
+            //TODO : rajouter les VisibilityEdges
+            return { simpleGroups: simple, metaGroups: meta };
+        });
+    }
+}
+exports.Tools = Tools;
+//# sourceMappingURL=tools.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/tools.js.map b/tsbuild/src/graphql/models/tools.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..9b29b1f69c636f96d22c8a8c77e556e85a1bbe78
--- /dev/null
+++ b/tsbuild/src/graphql/models/tools.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../../src/graphql/models/tools.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/userModel.js b/tsbuild/src/graphql/models/userModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..38ff489209a94771ded360ebe5e8a832aff22de6
--- /dev/null
+++ b/tsbuild/src/graphql/models/userModel.js
@@ -0,0 +1,109 @@
+"use strict";
+/**
+ * @file Fonctions qui implémentent les requetes relatives aux utilisateurs
+ * @author ofacklam
+ * @memberof GraphQL
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const users_1 = require("../object_resolvers/users");
+const user_1 = require("../../ldap/export/user");
+const apollo_server_core_1 = require("apollo-server-core");
+class UserModel {
+    /**
+     * @memberof GraphQL
+     * @class UserModel
+     * @summary Requetes relatives aux utilisateurs.
+     * @classdesc Cette classe contient les méthodes implémentant les requetes relatives aux utilisateurs.
+     * @arg {string} contextUser - L'identifiant de l'utilisateur du 'context'
+     */
+    constructor(contextUser) {
+        this.contextUser = contextUser;
+    }
+    /**
+     * @memberof GraphQL.UserModel#
+     * @function getUser
+     * @summary Fonction qui renvoit un utilisateur donné.
+     * @arg {string} uid - Identifiant demandé.
+     * @return {Promise(User)} Renvoie l'utilisateur dont l'identifiant est 'uid'
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    getUser(uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return users_1.User.tryCreate(uid);
+        });
+    }
+    /**
+     * @memberof GraphQL.UserModel#
+     * @function searchTOL
+     * @summary Fonction qui recherche dans le TOL
+     * @arg {searchTOLArgs} args - les données de recherche
+     * @return {Promise(User[])} Renvoie une liste d'utilisateurs
+     * @async
+     * @rights connectedOrOnplatal
+     */
+    searchTOL(args) {
+        return __awaiter(this, void 0, void 0, function* () {
+            //TODO : correctly handle groups (in LDAP, a member can be stored as member, speaker or admin...)
+            const searchData = new user_1.userData();
+            searchData.givenName = args.givenName;
+            searchData.lastName = args.lastName;
+            searchData.nickname = args.nickname;
+            searchData.nationality = args.nationality;
+            searchData.members = args.groups;
+            searchData.phone = args.phone;
+            searchData.mail = args.mail;
+            searchData.address = args.address;
+            const userList = yield user_1.User.search(searchData);
+            return userList.map((uid) => new users_1.User(uid));
+        });
+    }
+    /**
+     * @memberof GraphQL.UserModel#
+     * @function editProfile
+     * @summary Fonction qui modifie le profil et renvoie l'utilisateur
+     * @arg {editProfileArgs} args - les données a modifier
+     * @return {Promise(User)} Renvoie l'utilisateur mis a jour
+     * @async
+     * @rights authenticated
+     */
+    editProfile(args) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let data = yield user_1.User.peek(this.contextUser);
+            //Modify some fields, keep the others
+            let editArgs = new user_1.userData();
+            editArgs.uid = data.uid;
+            editArgs.password = data.password;
+            editArgs.givenName = data.givenName;
+            editArgs.lastName = data.lastName;
+            editArgs.nickname = args.nickname; // <- this field is modified by user
+            editArgs.gender = data.gender;
+            editArgs.photo = data.photo;
+            editArgs.phone = args.phone; // <- this field is modified
+            editArgs.address = data.address; // WTF why can't this be changed ????
+            editArgs.mail = args.mail; // <- this field is modified
+            editArgs.birthdate = data.birthdate;
+            editArgs.nationality = data.nationality;
+            editArgs.admins = data.admins;
+            editArgs.speakers = data.speakers;
+            editArgs.members = data.members;
+            editArgs.followers = data.followers;
+            if (yield user_1.User.edit(editArgs)) {
+                return new users_1.User(data.uid);
+            }
+            else {
+                throw new apollo_server_core_1.ApolloError("Edit failed");
+            }
+        });
+    }
+}
+exports.UserModel = UserModel;
+//# sourceMappingURL=userModel.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/models/userModel.js.map b/tsbuild/src/graphql/models/userModel.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..5e32372fc364b83c35e247d0a642e362e1bb01ca
--- /dev/null
+++ b/tsbuild/src/graphql/models/userModel.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"userModel.js","sourceRoot":"","sources":["../../../../src/graphql/models/userModel.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/groups.js b/tsbuild/src/graphql/object_resolvers/groups.js
new file mode 100644
index 0000000000000000000000000000000000000000..13363d7fe6cedf0d7f2f63feec77a8b90f67543c
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/groups.js
@@ -0,0 +1,736 @@
+"use strict";
+/**
+ * @file Resolvers des groupes
+ * @author ofacklam
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const users_1 = require("./users");
+const group_1 = require("../../ldap/export/group");
+const knex_router_1 = __importDefault(require("../../../db/knex_router"));
+const apollo_server_core_1 = require("apollo-server-core");
+class Group {
+    /**
+     * @abstract
+     * @memberof GraphQL
+     * @class Group
+     * @summary Resolvers des groupes
+     * @classdesc Une classe abstraite représentant l'interface group du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {string} gid - Identifiant du groupe, supposé valide
+     * @rights connectedOrOnplatal
+     */
+    constructor(gid) {
+        this.gid = gid;
+        this.m_dataLoaded = false;
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Group#
+     * @function __resolveType
+     * @summary Renvoie si c'est un SimpleGroup ou un MetaGroup
+     * @return {string}
+     * @rights connectedOrOnplatal
+     */
+    __resolveType(args, context, info) {
+        if (this instanceof SimpleGroup) {
+            return "SimpleGroup";
+        }
+        else if (this instanceof MetaGroup) {
+            return "MetaGroup";
+        }
+        else {
+            throw new apollo_server_core_1.ApolloError("Bad group type");
+        }
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function createdAt
+     * @summary Renvoie la date de création
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    createdAt(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_createdAt;
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function updatedAt
+     * @summary Renvoie la date de mise a jour
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    updatedAt(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_updatedAt;
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function name
+     * @summary Renvoie le nom du groupe
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    name(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_name;
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function description
+     * @summary Renvoie la description du groupe
+     * @return {Promise(string)}
+     * @rights viewer
+     * @async
+     */
+    description(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_description;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function mail
+     * @summary Renvoie l'adresse mail
+     * @return {Promise(string)}
+     * @rights viewer
+     * @async
+     */
+    mail(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_mail;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function website
+     * @summary Renvoie l'adresse du site web
+     * @return {Promise(string)}
+     * @rights viewer
+     * @async
+     */
+    website(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_website;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function frontPage
+     * @summary Renvoie la page principale
+     * @return {Promise(string)}
+     * @rights viewer
+     * @async
+     */
+    frontPage(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_frontPage;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function questions
+     * @summary Renvoie les questions adressées a ce groupe
+     * @return {Promise(Question[])}
+     * @rights viewer
+     * @async
+     */
+    questions(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+                // let result = await knex('questions').select().whereIn('id', received_messages);
+                // for(let entry of result){
+                //     entry.type = "Question";
+                // }
+                // return result;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function answers
+     * @summary Renvoie les réponses de ce groupe
+     * @return {Promise(Answer[])}
+     * @rights viewer
+     * @async
+     */
+    answers(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+                // let received_messages = await selectors.recievedMessages(user, groupUID);
+                // let result = await knex('answers').select().whereIn('id', received_messages);
+                // for(let entry of result){
+                //     entry.type = "Answer";
+                // }
+                // return result;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function announcementsFromGroup
+     * @summary Renvoie les annonces créées par ce groupe
+     * @return {Promise(Announcement[])}
+     * @rights member
+     * @async
+     */
+    announcementsFromGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function announcementsToGroup
+     * @summary Renvoie les annonces adressées a ce groupe
+     * @return {Promise(Announcement[])}
+     * @rights member
+     * @async
+     */
+    announcementsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function eventsFromGroup
+     * @summary Renvoie les evenements créés par ce groupe
+     * @return {Promise(Event[])}
+     * @rights member
+     * @async
+     */
+    eventsFromGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function eventsToGroup
+     * @summary Renvoie les evenements adressées a ce groupe
+     * @return {Promise(Event[])}
+     * @rights member
+     * @async
+     */
+    eventsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function privatePosts
+     * @summary Renvoie les posts internes du groupe
+     * @return {Promise(PrivatePost[])}
+     * @rights member
+     * @async
+     */
+    privatePosts(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function postsSummary
+     * @summary Renvoie le résumé interne
+     * @return {Promise(string)}
+     * @rights member
+     * @async
+     */
+    postsSummary(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isMember(this.gid)) {
+                yield this.fetchData();
+                return this.m_postsSummary;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a member");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function requestsToGroup
+     * @summary Renvoie toutes les requetes adressées au groupe.
+     * @return {Promise(Request[])}
+     * @rights admin
+     * @async
+     */
+    requestsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isAdmin(this.gid)) {
+                return context.models.request.getRequestsToGroup(this.gid);
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not an admin");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function userJoinGroupRequestsToGroup
+     * @summary Renvoie toutes les requetes UserJoinGroup adressées au groupe.
+     * @return {Promise(UserJoinGroup[])}
+     * @rights admin
+     * @async
+     */
+    userJoinGroupRequestsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isAdmin(this.gid)) {
+                return context.models.request.getUserJoinGroupRequestsToGroup(this.gid);
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not an admin");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function groupJoinMetagroupRequestsToGroup
+     * @summary Renvoie toutes les requetes GroupJoinMetagroup adressées au groupe.
+     * @return {Promise(GroupJoinMetagroup[])}
+     * @rights admin
+     * @async
+     */
+    groupJoinMetagroupRequestsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isAdmin(this.gid)) {
+                return context.models.request.getGroupJoinMetagroupRequestsToGroup(this.gid);
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not an admin");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function groupCoauthorEventRequestsToGroup
+     * @summary Renvoie toutes les requetes GroupCoauthorEvent adressées au groupe.
+     * @return {Promise(GroupCoauthorEvent[])}
+     * @rights admin
+     * @async
+     */
+    groupCoauthorEventRequestsToGroup(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isAdmin(this.gid)) {
+                return context.models.request.getGroupCoauthorEventRequestsToGroup(this.gid);
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not an admin");
+        });
+    }
+    /**
+     * @memberof GraphQL.Group#
+     * @function visibilityEdges
+     * @summary Renvoie les groupes auxquels ce groupe est visible.
+     * @return {Promise(Group[])}
+     * @rights viewer
+     * @async
+     */
+    visibilityEdges(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+}
+exports.Group = Group;
+class SimpleGroup extends Group {
+    /**
+     * @memberof GraphQL
+     * @class SimpleGroup
+     * @extends GraphQL.Group
+     * @summary Resolvers des groupes simples
+     * @classdesc Une classe représentant le type SimpleGroup du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {string} gid - Identifiant du groupe simple, supposé valide.
+     * @rights connectedOrOnplatal
+     */
+    constructor(gid) {
+        super(gid);
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer le groupe simple correspondant
+     * @arg {string} gid - Identifiant du groupe simple, sans hypothese sur la validité.
+     * @returns {Promise(SimpleGroup)} - Renvoie le groupe simple créé, ou null en cas d'erreur.
+     * @rights connectedOrOnplatal
+     * @async
+     * @static
+     */
+    static tryCreate(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let g = new SimpleGroup(gid);
+            if (yield g.fetchData()) {
+                return g;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce groupe simple dans le LDAP, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                try {
+                    let data = yield group_1.Group.peek(this.gid);
+                    if (data.gid !== this.gid) {
+                        throw "Error in search";
+                    }
+                    //this.m_createdAt = data.createdAt;
+                    //this.m_updatedAt = data.updatedAt;
+                    this.m_name = data.name;
+                    this.m_description = data.description;
+                    //this.m_mail = data.mail;
+                    //this.m_website = data.website;
+                    this.m_members = data.members;
+                    //this.m_speakers = data.speakers;
+                    this.m_admins = data.admins;
+                    //this.m_likers = data.likers;
+                    //this.m_frontPage = data.frontPage;
+                    //this.m_postsSummary = data.postsSummary;
+                    //this.m_parent = data.parent;
+                    //this.m_children = data.children;
+                    //this.m_school = ???;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                catch (_a) {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function members
+     * @summary Renvoie la liste des membres
+     * @return {Promise(User[])}
+     * @rights viewer
+     * @async
+     */
+    members(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_members.map(uid => {
+                    return new users_1.User(uid);
+                });
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function speakers
+     * @summary Renvoie la liste des speakers
+     * @return {Promise(User[])}
+     * @rights viewer
+     * @async
+     */
+    speakers(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_speakers.map(uid => {
+                    return new users_1.User(uid);
+                });
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function admins
+     * @summary Renvoie la liste des admins
+     * @return {Promise(User[])}
+     * @rights viewer
+     * @async
+     */
+    admins(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_admins.map(uid => {
+                    return new users_1.User(uid);
+                });
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function likers
+     * @summary Renvoie la liste des sympathisants
+     * @return {Promise(User[])}
+     * @rights viewer
+     * @async
+     */
+    likers(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_likers.map(uid => {
+                    return new users_1.User(uid);
+                });
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function parent
+     * @summary Renvoie le groupe parent
+     * @return {Promise(SimpleGroup)}
+     * @rights viewer
+     * @async
+     */
+    parent(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                if (this.m_parent == 'root') {
+                    return null;
+                }
+                else {
+                    return new SimpleGroup(this.m_parent);
+                }
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function children
+     * @summary Renvoie la liste des groupes enfants
+     * @return {Promise(SimpleGroup[])}
+     * @rights viewer
+     * @async
+     */
+    children(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_children.map(gid => {
+                    return new SimpleGroup(gid);
+                });
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function memberOfMeta
+     * @summary Renvoie la liste des méta-groupes dont ce groupe fait partie
+     * @return {Promise(MetaGroup[])}
+     * @rights viewer
+     * @async
+     */
+    memberOfMeta(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.SimpleGroup#
+     * @function school
+     * @summary Renvoie l'école d'origine
+     * @return {Promise(string)}
+     * @rights viewer
+     * @async
+     */
+    school(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                yield this.fetchData();
+                return this.m_school;
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+}
+exports.SimpleGroup = SimpleGroup;
+class MetaGroup extends Group {
+    /**
+     * @memberof GraphQL
+     * @class MetaGroup
+     * @extends GraphQL.Group
+     * @summary Resolvers des méta-groupes
+     * @classdesc Une classe représentant le type MetaGroup du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {string} gid - Identifiant du méta-groupe, supposé valide
+     * @rights connectedOrOnplatal
+     */
+    constructor(gid) {
+        super(gid);
+    }
+    /**
+     * @memberof GraphQL.MetaGroup#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer le méta-groupe correspondant
+     * @arg {string} gid - Identifiant du méta-groupe, sans hypothese sur la validité.
+     * @returns {Promise(MetaGroup)} - Renvoie le méta-groupe créé, ou null en cas d'erreur.
+     * @rights connectedOrOnplatal
+     * @async
+     * @static
+     */
+    static tryCreate(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let g = new MetaGroup(gid);
+            if (yield g.fetchData()) {
+                return g;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.MetaGroup#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce méta-groupe dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'name', 'description', 
+                //'mail', 
+                //'posts_summary', 
+                //'front_page', 
+                'website').from('groups').where('gid', this.gid);
+                if (data.length > 0) {
+                    let g = data[0];
+                    this.m_createdAt = g.created_at;
+                    this.m_updatedAt = g.updated_at;
+                    this.m_name = g.name;
+                    this.m_description = g.description;
+                    //this.m_mail = g.mail;
+                    this.m_website = g.website;
+                    //this.m_frontPage = g.frontPage;
+                    //this.m_postsSummary = g.postsSummary;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.MetaGroup#
+     * @function admins
+     * @summary Renvoie la liste des admins
+     * @return {Promise(User[])}
+     * @rights viewer
+     * @async
+     */
+    admins(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+    /**
+     * @memberof GraphQL.MetaGroup#
+     * @function members
+     * @summary Renvoie la liste des groupes membres
+     * @return {Promise(SimpleGroup[])}
+     * @rights viewer
+     * @async
+     */
+    members(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (context.models.auth.isViewer(this.gid)) {
+                throw "Not implemented";
+                /*let member_group_list = await knex.distinct().select().from('groups')
+                    .innerJoin('meta_group_membership', 'groups.uid', 'meta_group_membership.member_uid')
+                    .where('meta_group_membership.union_uid', '=', group.gid);
+                let members = new Set;
+                for (const memberGroup of member_group_list) {
+                    let res = await getGroupMemberUsers(quser, new Group(memberGroup));
+                    for (const member of res.values()) {
+                        members.add(member);
+                    }
+                }
+                return members;*/
+            }
+            throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+        });
+    }
+}
+exports.MetaGroup = MetaGroup;
+//# sourceMappingURL=groups.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/groups.js.map b/tsbuild/src/graphql/object_resolvers/groups.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..fa70c8d03f1731140bbd66a4aee08eaba996fadb
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/groups.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../../../src/graphql/object_resolvers/groups.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/messages.js b/tsbuild/src/graphql/object_resolvers/messages.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e190a5fba958ce2c9d06614966f9d742c09788c
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/messages.js
@@ -0,0 +1,762 @@
+"use strict";
+/**
+ * @file Resolvers pour tous les types de messages
+ * @author akka, ofacklam
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const users_1 = require("./users");
+const knex_router_1 = __importDefault(require("../../../db/knex_router"));
+const apollo_server_core_1 = require("apollo-server-core");
+class Message {
+    /**
+     * @memberof GraphQL
+     * @class Message
+     * @summary Resolvers des messages
+     * @classdesc Une classe abstraite représentant l'interface Message du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights dépend du type de message
+     * @abstract
+     */
+    constructor(mid) {
+        this.mid = mid;
+        this.m_dataLoaded = false;
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Message#
+     * @function __resolveType
+     * @summary Renvoie quel type de Message c'est
+     * @return {string}
+     * @rights same as message object
+     */
+    __resolveType() {
+        if (this instanceof Announcement) {
+            return "Announcement";
+        }
+        else if (this instanceof Event) {
+            return "Event";
+        }
+        else if (this instanceof Question) {
+            return "Question";
+        }
+        else if (this instanceof Answer) {
+            return "Answer";
+        }
+        else if (this instanceof PrivatePost) {
+            return "PrivatePost";
+        }
+        else {
+            throw new apollo_server_core_1.ApolloError("Bad message type");
+        }
+    }
+    /**
+     * @memberof GraphQL.Message#
+     * @function createdAt
+     * @summary Renvoie la date de création
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    createdAt(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_createdAt;
+        });
+    }
+    /**
+     * @memberof GraphQL.Message#
+     * @function updatedAt
+     * @summary Renvoie la date de mise a jour
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    updatedAt(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_updatedAt;
+        });
+    }
+    /**
+     * @memberof GraphQL.Message#
+     * @function title
+     * @summary Renvoie le titre du message
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    title(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_title;
+        });
+    }
+    /**
+     * @memberof GraphQL.Message#
+     * @function content
+     * @summary Renvoie le contenu du message
+     * @return {Promise(string)}
+     * @rights same as message object
+     * @async
+     */
+    content(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_content;
+        });
+    }
+}
+exports.Message = Message;
+class Announcement extends Message {
+    /**
+     * @memberof GraphQL
+     * @class Announcement
+     * @extends GraphQL.Message
+     * @summary Resolvers des announcements
+     * @classdesc Une classe représentant le type Announcement du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    constructor(mid) {
+        super(mid);
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer l'annonce correspondante
+     * @arg {number} mid - Identifiant du message, sans hypothese sur la validité.
+     * @returns {Promise(Announcement)} - Renvoie le Announcement créé, ou null en cas d'erreur.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     * @static
+     */
+    static tryCreate(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let m = new Announcement(mid);
+            if (yield m.fetchData()) {
+                return m;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cet announcement dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'title', 'content', 
+                //'importance', 
+                'views').from('messages_announcements').where('mid', this.mid);
+                if (data.length > 0) {
+                    let m = data[0];
+                    this.m_createdAt = m.created_at;
+                    this.m_updatedAt = m.updated_at;
+                    this.m_title = m.title;
+                    this.m_content = m.content;
+                    //this.m_importance = m.importance;
+                    this.m_views = m.views;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function authors
+     * @summary Renvoie les groupes auteurs
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    authors(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*return knex.select({ uid: 'group' }).from('group_message_relationships')
+                .where('message', messageID).whereIn('status', ['host', 'publish']);*/
+        });
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function recipients
+     * @summary Renvoie les groupes destinataires
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    recipients(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*return knex.select({ uid: 'group' }).from('group_message_relationships')
+                .where('message', messageID).where('status', 'recieve');*/
+        });
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function importance
+     * @summary Renvoie l'importance
+     * @return {Promise(number)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    importance(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_importance;
+        });
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function views
+     * @summary Renvoie le nombre de vues
+     * @return {Promise(number)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    views(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_views;
+        });
+    }
+    /**
+     * @memberof GraphQL.Announcement#
+     * @function forEvent
+     * @summary Renvoie l'evenement correspondant, s'il existe
+     * @return {Promise(Event)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    forEvent(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let data = yield knex_router_1.default.select('mid').from('messages_events').where('for_announcement', this.mid);
+            if (data.length > 0) {
+                return new Event(data[0].mid);
+            }
+            return null;
+        });
+    }
+}
+exports.Announcement = Announcement;
+class Event extends Message {
+    /**
+     * @memberof GraphQL
+     * @class Event
+     * @extends GraphQL.Message
+     * @summary Resolvers des events
+     * @classdesc Une classe représentant le type Event du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     */
+    constructor(mid) {
+        super(mid);
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer l'evenement correspondant
+     * @arg {number} mid - Identifiant du message, sans hypothese sur la validité.
+     * @returns {Promise(Event)} - Renvoie le Event créé, ou null en cas d'erreur.
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     * @static
+     */
+    static tryCreate(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let m = new Event(mid);
+            if (yield m.fetchData()) {
+                return m;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cet event dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'title', 'content', 'location', 'start_time', 'end_time', 'for_announcement').from('messages_events').where('mid', this.mid);
+                if (data.length > 0) {
+                    let m = data[0];
+                    this.m_createdAt = m.created_at;
+                    this.m_updatedAt = m.updated_at;
+                    this.m_title = m.title;
+                    this.m_content = m.content;
+                    this.m_location = m.location;
+                    this.m_startTime = m.start_time;
+                    this.m_endTime = m.end_time;
+                    this.m_forAnnouncement = m.for_announcement;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Event#
+     * @function authors
+     * @summary Renvoie les groupes auteurs
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    authors(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*return knex.select({ uid: 'group' }).from('group_message_relationships')
+                .where('message', messageID).whereIn('status', ['host', 'publish']);*/
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function recipients
+     * @summary Renvoie les groupes destinataires
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    recipients(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+            /*return knex.select({ uid: 'group' }).from('group_message_relationships')
+                .where('message', messageID).where('status', 'recieve');*/
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function location
+     * @summary Renvoie l'endroit
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    location(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_location;
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function startTime
+     * @summary Renvoie l'horaire de début
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    startTime(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_startTime;
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function endTime
+     * @summary Renvoie l'horaire de fin
+     * @return {Promise(string)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    endTime(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_endTime;
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function participatingGroups
+     * @summary Renvoie les groupes qui participent
+     * @return {Promise(Group[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    participatingGroups(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function participatingUsers
+     * @summary Renvoie les users qui participent
+     * @return {Promise(User[])}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    participatingUsers(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.Event#
+     * @function forAnnouncement
+     * @summary Renvoie l'announcement correspondant, s'il existe
+     * @return {Promise(Announcement)}
+     * @rights membre d'un groupe author ou d'un groupe recipient
+     * @async
+     */
+    forAnnouncement(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            if (this.m_forAnnouncement == 0) { //what is the default ?????
+                return null;
+            }
+            else {
+                return new Announcement(this.m_forAnnouncement);
+            }
+        });
+    }
+}
+exports.Event = Event;
+class PrivatePost extends Message {
+    /**
+     * @memberof GraphQL
+     * @class PrivatePost
+     * @extends GraphQL.Message
+     * @summary Resolvers des posts privés
+     * @classdesc Une classe représentant le type PrivatePost du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights membre du groupe recipient
+     */
+    constructor(mid) {
+        super(mid);
+    }
+    /**
+     * @memberof GraphQL.PrivatePost#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer le post privé correspondant
+     * @arg {number} mid - Identifiant du message, sans hypothese sur la validité.
+     * @returns {Promise(PrivatePost)} - Renvoie le PrivatePost créé, ou null en cas d'erreur.
+     * @rights membre du groupe recipient
+     * @async
+     * @static
+     */
+    static tryCreate(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let m = new PrivatePost(mid);
+            if (yield m.fetchData()) {
+                return m;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.PrivatePost#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'title', 'content', 'author', 'recipient').from('messages_private_posts').where('mid', this.mid);
+                if (data.length > 0) {
+                    let m = data[0];
+                    this.m_createdAt = m.created_at;
+                    this.m_updatedAt = m.updated_at;
+                    this.m_title = m.title;
+                    this.m_content = m.content;
+                    this.m_author = m.author;
+                    this.m_recipient = m.recipient;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.PrivatePost#
+     * @function author
+     * @summary Renvoie le user auteur
+     * @return {Promise(User)}
+     * @rights membre du groupe recipient
+     * @async
+     */
+    author(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new users_1.User(this.m_author);
+        });
+    }
+    /**
+     * @memberof GraphQL.PrivatePost#
+     * @function recipient
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(Group)}
+     * @rights membre du groupe recipient
+     * @async
+     */
+    recipient(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+}
+exports.PrivatePost = PrivatePost;
+class Question extends Message {
+    /**
+     * @memberof GraphQL
+     * @class Question
+     * @extends GraphQL.Message
+     * @summary Resolvers des questions
+     * @classdesc Une classe représentant le type Question du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights viewer du groupe recipient
+     */
+    constructor(mid) {
+        super(mid);
+    }
+    /**
+     * @memberof GraphQL.Question#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer la question correspondante
+     * @arg {number} mid - Identifiant du message, sans hypothese sur la validité.
+     * @returns {Promise(Question)} - Renvoie la Question créée, ou null en cas d'erreur.
+     * @rights viewer du groupe recipient
+     * @async
+     * @static
+     */
+    static tryCreate(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let m = new Question(mid);
+            if (yield m.fetchData()) {
+                return m;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.Question#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'title', 'content', 'author', 'recipient').from('messages_questions').where('mid', this.mid);
+                if (data.length > 0) {
+                    let m = data[0];
+                    this.m_createdAt = m.created_at;
+                    this.m_updatedAt = m.updated_at;
+                    this.m_title = m.title;
+                    this.m_content = m.content;
+                    this.m_author = m.author;
+                    this.m_recipient = m.recipient;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Question#
+     * @function author
+     * @summary Renvoie le user auteur
+     * @return {Promise(User)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    author(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new users_1.User(this.m_author);
+        });
+    }
+    /**
+     * @memberof GraphQL.Question#
+     * @function recipient
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(Group)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    recipient(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.Question#
+     * @function forAnswer
+     * @summary Renvoie la réponse correspondante, si elle existe
+     * @return {Promise(Answer)}
+     * @rights viewer du groupe recipient
+     * @async
+     */
+    forAnswer(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let data = yield knex_router_1.default.select('mid').from('messages_answers').where('for_question', this.mid);
+            if (data.length > 0) {
+                return new Answer(data[0].mid);
+            }
+            return null;
+        });
+    }
+}
+exports.Question = Question;
+class Answer extends Message {
+    /**
+     * @memberof GraphQL
+     * @class Answer
+     * @extends GraphQL.Message
+     * @summary Resolvers des réponses
+     * @classdesc Une classe représentant le type Answer du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} mid - Identifiant du message, supposé valide.
+     * @rights viewer du groupe author
+     */
+    constructor(mid) {
+        super(mid);
+    }
+    /**
+     * @memberof GraphQL.Answer#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer la réponse correspondante
+     * @arg {number} mid - Identifiant du message, sans hypothese sur la validité.
+     * @returns {Promise(Answer)} - Renvoie la Answer créée, ou null en cas d'erreur.
+     * @rights viewer du groupe author
+     * @async
+     * @static
+     */
+    static tryCreate(mid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let m = new Answer(mid);
+            if (yield m.fetchData()) {
+                return m;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.Answer#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce post privé dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('created_at', 'updated_at', 'title', 'content', 'recipient', //<--- WTF ????
+                'for_question').from('messages_answers').where('mid', this.mid);
+                if (data.length > 0) {
+                    let m = data[0];
+                    this.m_createdAt = m.created_at;
+                    this.m_updatedAt = m.updated_at;
+                    this.m_title = m.title;
+                    this.m_content = m.content;
+                    this.m_author = m.recipient;
+                    this.m_forQuestion = m.for_question;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Answer#
+     * @function author
+     * @summary Renvoie le groupe auteur
+     * @return {Promise(Group)}
+     * @rights viewer du groupe author
+     * @async
+     */
+    author(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.Answer#
+     * @function forQuestion
+     * @summary Renvoie la question correspondante
+     * @return {Promise(Question)}
+     * @rights viewer du groupe author
+     * @async
+     */
+    forQuestion(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new Question(this.m_forQuestion);
+        });
+    }
+}
+exports.Answer = Answer;
+//# sourceMappingURL=messages.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/messages.js.map b/tsbuild/src/graphql/object_resolvers/messages.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..fd84eb240876b793f5874dd857e966d3ac5c89f3
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/messages.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../src/graphql/object_resolvers/messages.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/requests.js b/tsbuild/src/graphql/object_resolvers/requests.js
new file mode 100644
index 0000000000000000000000000000000000000000..a926a7b76cc758f2d1383444828a627a83434c26
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/requests.js
@@ -0,0 +1,374 @@
+"use strict";
+/**
+ * @file Resolvers pour tous les types de messages
+ * @author akka, ofacklam
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const groups_1 = require("./groups");
+const users_1 = require("./users");
+const messages_1 = require("./messages");
+const knex_router_1 = __importDefault(require("../../../db/knex_router"));
+const apollo_server_core_1 = require("apollo-server-core");
+class Request {
+    /**
+     * @memberof GraphQL
+     * @class Request
+     * @summary Resolvers des requetes
+     * @classdesc Une classe abstraite représentant l'interface Request du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} rid - Identifiant de la requete, supposé valide.
+     * @rights dépend du type de requete
+     * @abstract
+     */
+    constructor(rid) {
+        this.rid = rid;
+        this.m_dataLoaded = false;
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.Request#
+     * @function __resolveType
+     * @summary Renvoie quel type de Request c'est
+     * @return {string}
+     * @rights same as request object
+     */
+    __resolveType() {
+        if (this instanceof UserJoinGroup) {
+            return "UserJoinGroup";
+        }
+        else if (this instanceof GroupJoinMetagroup) {
+            return "GroupJoinMetagroup";
+        }
+        else if (this instanceof GroupCoauthorEvent) {
+            return "GroupCoauthorEvent";
+        }
+        else {
+            throw new apollo_server_core_1.ApolloError("Bad request type");
+        }
+    }
+    /**
+     * @memberof GraphQL.Request#
+     * @function comment
+     * @summary Renvoie le commentaire associé
+     * @return {Promise(string)}
+     * @rights same as request object
+     * @async
+     */
+    comment(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_comment;
+        });
+    }
+}
+exports.Request = Request;
+class UserJoinGroup extends Request {
+    /**
+     * @memberof GraphQL
+     * @class UserJoinGroup
+     * @extends GraphQL.Request
+     * @summary Resolvers des requetes UserJoinGroup
+     * @classdesc Une classe représentant le type UserJoinGroup du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} rid - Identifiant de la requete, supposé valide.
+     * @rights admin du groupe recipient ou le user émetteur
+     */
+    constructor(rid) {
+        super(rid);
+    }
+    /**
+     * @memberof GraphQL.UserJoinGroup#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer la requete correspondante
+     * @arg {number} rid - Identifiant de la requete, sans hypothese sur la validité.
+     * @returns {Promise(UserJoinGroup)} - Renvoie le UserJoinGroup créé, ou null en cas d'erreur.
+     * @rights admin du groupe recipient ou le user émetteur
+     * @async
+     * @static
+     */
+    static tryCreate(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let r = new UserJoinGroup(rid);
+            if (yield r.fetchData()) {
+                return r;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.UserJoinGroup#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cette requete dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('request_comment', 'request_from', 'request_to').from('requests_user_join_group').where('rid', this.rid);
+                if (data.length > 0) {
+                    let r = data[0];
+                    this.m_comment = r.request_comment;
+                    this.m_from = r.request_from;
+                    this.m_to = r.request_to;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.UserJoinGroup#
+     * @function from
+     * @summary Renvoie le user émetteur
+     * @return {Promise(User)}
+     * @rights admin du groupe recipient ou le user émetteur
+     * @async
+     */
+    from(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new users_1.User(this.m_from);
+        });
+    }
+    /**
+     * @memberof GraphQL.UserJoinGroup#
+     * @function to
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(SimpleGroup)}
+     * @rights admin du groupe recipient ou le user émetteur
+     * @async
+     */
+    to(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new groups_1.SimpleGroup(this.m_to);
+        });
+    }
+}
+exports.UserJoinGroup = UserJoinGroup;
+class GroupJoinMetagroup extends Request {
+    /**
+     * @memberof GraphQL
+     * @class GroupJoinMetagroup
+     * @extends GraphQL.Request
+     * @summary Resolvers des requetes GroupJoinMetagroup
+     * @classdesc Une classe représentant le type GroupJoinMetagroup du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} rid - Identifiant de la requete, supposé valide.
+     * @rights admin du groupe émetteur ou destinataire
+     */
+    constructor(rid) {
+        super(rid);
+    }
+    /**
+     * @memberof GraphQL.GroupJoinMetagroup#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer la requete correspondante
+     * @arg {number} rid - Identifiant de la requete, sans hypothese sur la validité.
+     * @returns {Promise(GroupJoinMetagroup)} - Renvoie le GroupJoinMetagroup créé, ou null en cas d'erreur.
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     * @static
+     */
+    static tryCreate(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let r = new GroupJoinMetagroup(rid);
+            if (yield r.fetchData()) {
+                return r;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupJoinMetagroup#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cette requete dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('request_comment', 'request_from', 'request_to').from('requests_group_join_metagroup').where('rid', this.rid);
+                if (data.length > 0) {
+                    let r = data[0];
+                    this.m_comment = r.request_comment;
+                    this.m_from = r.request_from;
+                    this.m_to = r.request_to;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.GroupJoinMetagroup#
+     * @function from
+     * @summary Renvoie le groupe émetteur
+     * @return {Promise(SimpleGroup)}
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     */
+    from(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new groups_1.SimpleGroup(this.m_from);
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupJoinMetagroup#
+     * @function to
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(MetaGroup)}
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     */
+    to(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return new groups_1.MetaGroup(this.m_to);
+        });
+    }
+}
+exports.GroupJoinMetagroup = GroupJoinMetagroup;
+class GroupCoauthorEvent extends Request {
+    /**
+     * @memberof GraphQL
+     * @class GroupCoauthorEvent
+     * @extends GraphQL.Request
+     * @summary Resolvers des requetes GroupCoauthorEvent
+     * @classdesc Une classe représentant le type GroupCoauthorEvent du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {number} rid - Identifiant de la requete, supposé valide.
+     * @rights admin du groupe émetteur ou destinataire
+     */
+    constructor(rid) {
+        super(rid);
+    }
+    /**
+     * @memberof GraphQL.GroupCoauthorEvent#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer la requete correspondante
+     * @arg {number} rid - Identifiant de la requete, sans hypothese sur la validité.
+     * @returns {Promise(GroupCoauthorEvent)} - Renvoie le GroupCoauthorEvent créé, ou null en cas d'erreur.
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     * @static
+     */
+    static tryCreate(rid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let r = new GroupCoauthorEvent(rid);
+            if (yield r.fetchData()) {
+                return r;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupCoauthorEvent#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur cette requete dans la BDD, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                let data = yield knex_router_1.default.select('request_comment', 'request_from', 'request_to', 'for_event').from('requests_group_coauthor_event').where('rid', this.rid);
+                if (data.length > 0) {
+                    let r = data[0];
+                    this.m_comment = r.request_comment;
+                    this.m_from = r.request_from;
+                    this.m_to = r.request_to;
+                    this.m_forEvent = r.for_event;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                else {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * Ci-dessous les resolvers a proprement parler.
+     */
+    /**
+     * @memberof GraphQL.GroupCoauthorEvent#
+     * @function from
+     * @summary Renvoie le groupe émetteur
+     * @return {Promise(Group)}
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     */
+    from(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupCoauthorEvent#
+     * @function to
+     * @summary Renvoie le groupe destinataire
+     * @return {Promise(Group)}
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     */
+    to(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.GroupCoauthorEvent#
+     * @function forEvent
+     * @summary Renvoie l'evenement a co-organiser
+     * @return {Promise(Event)}
+     * @rights admin du groupe émetteur ou destinataire
+     * @async
+     */
+    forEvent(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+            //a-t-il le droit de voir ???
+            return new messages_1.Event(this.m_forEvent);
+        });
+    }
+}
+exports.GroupCoauthorEvent = GroupCoauthorEvent;
+//# sourceMappingURL=requests.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/requests.js.map b/tsbuild/src/graphql/object_resolvers/requests.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..59cdba38f96553007cbecf14dc0df630c8e635c3
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/requests.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"requests.js","sourceRoot":"","sources":["../../../../src/graphql/object_resolvers/requests.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/users.js b/tsbuild/src/graphql/object_resolvers/users.js
new file mode 100644
index 0000000000000000000000000000000000000000..706ecac6481170b635cf39e3acee85f542a0a478
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/users.js
@@ -0,0 +1,323 @@
+"use strict";
+/**
+ * @file Resolvers des utilisateurs
+ * @author ofacklam
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const groups_1 = require("./groups");
+const user_1 = require("../../ldap/export/user");
+const tools_1 = require("../models/tools");
+class User {
+    /**
+     * @memberof GraphQL
+     * @class User
+     * @summary Resolvers des utilisateurs
+     * @classdesc Une classe représentant le type User du schéma.
+     * Comme Apollo Server, par défaut, appelle la propriété / fonction avec le nom a résoudre, il n'y a pas besoin d'écrire les resolvers explicitement.
+     * @arg {string} uid - Identifiant du user, supposé valide.
+     * @rights connectedOrOnplatal
+     */
+    constructor(uid) {
+        this.uid = uid;
+        this.m_dataLoaded = false;
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function tryCreate
+     * @summary Fonction qui va essayer de créer le user correspondant
+     * @arg {string} uid - Identifiant du user, sans hypothese sur la validité.
+     * @returns {Promise(User)} - Renvoie le user créé, ou null en cas d'erreur.
+     * @rights connectedOrOnplatal
+     * @async
+     * @static
+     */
+    static tryCreate(uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let u = new User(uid);
+            if (yield u.fetchData()) {
+                return u;
+            }
+            return null;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function fetchData
+     * @summary Fonction qui va chercher toutes les données sur ce user dans le LDAP, si ce n'est pas déja fait.
+     * @returns {Promise(boolean)} Renvoie true si le chargement est réussi.
+     * @async
+     * @protected
+     */
+    fetchData() {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (!this.m_dataLoaded) {
+                try {
+                    let data = yield user_1.User.peek(this.uid);
+                    if (data.uid !== this.uid) {
+                        throw "Error in search";
+                    }
+                    this.m_givenName = data.givenName;
+                    this.m_lastName = data.lastName;
+                    this.m_nickname = data.nickname;
+                    this.m_nationality = data.nationality;
+                    this.m_birthdate = data.birthdate;
+                    this.m_mail = data.mail;
+                    this.m_phone = data.phone;
+                    this.m_address = data.address;
+                    this.m_memberOf = data.members;
+                    this.m_speakerOf = data.speakers;
+                    this.m_adminOf = data.admins;
+                    this.m_likes = data.followers;
+                    this.m_dataLoaded = true;
+                    return true;
+                }
+                catch (_a) {
+                    return false;
+                }
+            }
+            return true;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function givenName
+     * @summary Renvoie le prénom
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    givenName(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_givenName;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function lastName
+     * @summary Renvoie le nom de famille
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    lastName(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_lastName;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function nickname
+     * @summary Renvoie le surnom
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    nickname(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_nickname;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function nationality
+     * @summary Renvoie la nationalité
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    nationality(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_nationality;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function birthdate
+     * @summary Renvoie la date de naissance
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    birthdate(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_birthdate;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function promotion
+     * @summary Renvoie la promotion
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    promotion(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            throw "Not implemented";
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function mail
+     * @summary Renvoie l'adresse mail
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    mail(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_mail;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function phone
+     * @summary Renvoie le numéro de téléphone
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    phone(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_phone;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function address
+     * @summary Renvoie l'adresse
+     * @return {Promise(string)}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    address(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            return this.m_address;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function memberOf
+     * @summary Renvoie les groupes dont il est membre
+     * @return {Promise(Group[])}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    memberOf(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            let simple = new tools_1.GroupSet(this.m_memberOf);
+            let meta = yield tools_1.Tools.metaGroupsOfGroups(simple);
+            let all;
+            for (let gid of simple) {
+                all.push(new groups_1.SimpleGroup(gid));
+            }
+            for (let gid of meta) {
+                all.push(new groups_1.MetaGroup(gid));
+            }
+            return all;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function speakerOf
+     * @summary Renvoie les groupes dont il est speaker
+     * @return {Promise(Group[])}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    speakerOf(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            let speaker = new tools_1.GroupSet(this.m_speakerOf);
+            let admin = new tools_1.GroupSet(this.m_adminOf);
+            let meta = yield tools_1.Tools.metaGroupsOfGroups(admin);
+            let all;
+            for (let gid of speaker) {
+                all.push(new groups_1.SimpleGroup(gid));
+            }
+            for (let gid of meta) {
+                all.push(new groups_1.MetaGroup(gid));
+            }
+            return all;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function adminOf
+     * @summary Renvoie les groupes dont il est admin
+     * @return {Promise(Group[])}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    adminOf(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            let simple = new tools_1.GroupSet(this.m_adminOf);
+            let meta = yield tools_1.Tools.metaGroupsOfGroups(simple);
+            let all;
+            for (let gid of simple) {
+                all.push(new groups_1.SimpleGroup(gid));
+            }
+            for (let gid of meta) {
+                all.push(new groups_1.MetaGroup(gid));
+            }
+            return all;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function likes
+     * @summary Renvoie les groupes dont il est sympathisant
+     * @return {Promise(Group[])}
+     * @rights connectedOrOnplatal
+     * @async
+     */
+    likes(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            yield this.fetchData();
+            let simple = new tools_1.GroupSet(this.m_likes);
+            let meta = yield tools_1.Tools.metaGroupsOfGroups(simple);
+            let all;
+            for (let gid of simple) {
+                all.push(new groups_1.SimpleGroup(gid));
+            }
+            for (let gid of meta) {
+                all.push(new groups_1.MetaGroup(gid));
+            }
+            return all;
+        });
+    }
+    /**
+     * @memberof GraphQL.User#
+     * @function questionsFromUser
+     * @summary Renvoie les questions que le user a posées
+     * @return {Promise(Question[])}
+     * @rights viewer of recipient group
+     * @async
+     */
+    questionsFromUser(args, context, info) {
+        return __awaiter(this, void 0, void 0, function* () {
+            throw "Not implemented";
+        });
+    }
+}
+exports.User = User;
+//# sourceMappingURL=users.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/object_resolvers/users.js.map b/tsbuild/src/graphql/object_resolvers/users.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..654a83f5d0bd59471ddaae4f51ea000e29371735
--- /dev/null
+++ b/tsbuild/src/graphql/object_resolvers/users.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"users.js","sourceRoot":"","sources":["../../../../src/graphql/object_resolvers/users.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/graphql/resolvers.js b/tsbuild/src/graphql/resolvers.js
new file mode 100644
index 0000000000000000000000000000000000000000..ffb1ba1c4c282cbc20512f69094a10b04a44c4b6
--- /dev/null
+++ b/tsbuild/src/graphql/resolvers.js
@@ -0,0 +1,673 @@
+"use strict";
+/**
+ * @file Résolveurs des requêtes GraphQL.
+ * @author akka vodol, ofacklam
+ * @memberof GraphQL
+ * @desc On ne définit dans ce fichier que les resolvers pour les types Query et Mutations.
+ * En effet on exploite les default resolvers fournis par Apollo Server (le deuxième point) :
+ *
+ * > Explicit resolvers are not needed for every type, since Apollo Server provides a default that can perform two actions depending on the contents of parent:
+ * > - Return the property from parent with the relevant field name
+ * > - Calls a function on parent with the relevant field name and provide the remaining resolver parameters as arguments
+ * https://www.apollographql.com/docs/apollo-server/v2/essentials/data.html#default
+ *
+ * Dans notre cas, le type de retour de chaque resolver est un objet JS (Group, Message, Request ou User)
+ * défini dans un des fichiers de `./object_resolvers/` ; donc les méthodes des classes Group, Message, Request et User
+ * dont le prototype est (parent, args, context: Context, info) sont utilisées comme resolvers de l'objet GraphQL respectif.
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const apollo_server_core_1 = require("apollo-server-core");
+const requests_1 = require("./object_resolvers/requests");
+const tools_1 = require("./models/tools");
+exports.resolvers = {
+    Query: {
+        // User queries de base
+        // @rights connectedOrOnplatal
+        user: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isConnectedOrOnplatal()) {
+                    return context.models.user.getUser(args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // Group queries de base
+        // @rights connectedOrOnplatal
+        group: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isConnectedOrOnplatal()) {
+                    return context.models.group.getGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights connectedOrOnplatal
+        simpleGroup: function (obj, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isConnectedOrOnplatal()) {
+                    return context.models.group.getSimpleGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights connectedOrOnplatal
+        metaGroup: function (obj, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isConnectedOrOnplatal()) {
+                    return context.models.group.getMetaGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // Message queries de base
+        //message -> not implemented -> message(mid: ID!): Message
+        // @rights membre d'un groupe author ou d'un groupe recipient
+        announcement: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.message.getAnnouncement(args.mid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights membre d'un groupe author ou d'un groupe recipient
+        event: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.message.getEvent(args.mid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights membre du groupe recipient
+        privatePost: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.message.getPrivatePost(args.mid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights viewer du groupe recipient
+        question: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.message.getQuestion(args.mid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights viewer du groupe author
+        answer: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.message.getAnswer(args.mid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // Request queries de base
+        //request -> not implemented -> request(rid: ID!): Request
+        // @rights admin du groupe destinaire ou le user émetteur
+        userJoinGroupRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.request.getUserJoinGroupRequest(args.rid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights admin du groupe émetteur ou destinataire
+        groupJoinMetagroupRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.request.getGroupJoinMetagroupRequest(args.rid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // @rights admin du groupe émetteur ou destinataire
+        groupCoauthorEventRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                //TODO : verifier les autorisations
+                throw "Not implemented";
+                return context.models.request.getGroupCoauthorEventRequest(args.rid);
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        },
+        // Tous les Messages visibles par un utilisateur(dont le uid, et donc les autorisations, est passé par context)
+        // @rights member of groups
+        allMessages: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let groups = context.models.auth.groupsMember();
+                return context.models.message.getAllMessages(groups);
+            });
+        },
+        // @rights member of groups
+        allAnnouncements: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let groups = context.models.auth.groupsMember();
+                return context.models.message.getAllAnnouncements(groups);
+            });
+        },
+        // @rights member of groups
+        allEvents: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let groups = context.models.auth.groupsMember();
+                return context.models.message.getAllEvents(groups);
+            });
+        },
+        // @rights member of groups
+        allPrivatePosts: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let groups = context.models.auth.groupsMember();
+                return context.models.message.getAllPrivatePosts(groups);
+            });
+        },
+        // Tous les Groupes visibles par un utilisateur.
+        // Correspondrait au sous - champ "viewerOf" de User, volontairement non - défini comme tel.Tous les autres cas de figure sont couverts par les sous - champs "<permission>Of" de User
+        // @rights viewer of groups
+        allGroups: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let visibleGroupCollection = context.models.auth.groupsViewer();
+                return context.models.group.getAllGroupsByCollection(visibleGroupCollection);
+            });
+        },
+        // @rights viewer of groups
+        allSimpleGroups: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let visibleGroupCollection = context.models.auth.groupsViewer();
+                return context.models.group.getAllSimpleGroups(visibleGroupCollection.simpleGroups);
+            });
+        },
+        // @rights supervisor of groups
+        supervisorOf: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let supervisorGroupCollection = context.models.auth.groupsSupervisor();
+                return context.models.group.getAllGroupsByCollection(supervisorGroupCollection);
+            });
+        },
+        // TOL
+        // @rights connectedOrOnplatal
+        searchTOL: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isConnectedOrOnplatal()) {
+                    return context.models.user.searchTOL(args);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not connected or on-platal");
+            });
+        }
+    },
+    Mutation: {
+        // Groups - independent mutations
+        // @rights authenticated
+        editProfile: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAuthenticated()) {
+                    return context.models.user.editProfile(args);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not authenticated");
+            });
+        },
+        // Viewer mutations
+        // @rights viewer
+        likeGroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isViewer(args.gid)) {
+                    return context.models.group.likeGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights viewer
+        unlikeGroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isViewer(args.gid)) {
+                    return context.models.group.unlikeGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights member d'un groupe author ou recipient
+        userParticipate: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.userParticipate(context.user.uid, args.forEvent);
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights member d'un groupe author ou recipient
+        userUnparticipate: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.userUnparticipate(context.user.uid, args.forEvent);
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights viewer
+        userRequestJoinGroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isViewer(args.toGroup)) {
+                    return context.models.request.userRequestJoinGroup(args.toGroup, args.comment);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights viewer
+        createQuestion: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isViewer(args.toGroup)) {
+                    return context.models.message.createQuestion(args.toGroup, args.title, args.content);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights viewer du groupe et author de la question
+        editQuestion: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier qu'il est l'auteur de la question et viewer
+                return context.models.message.editQuestion(args.questionToEdit, args.title, args.content);
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // @rights viewer du groupe et author de la question
+        removeQuestion: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier qu'il est l'auteur de la question et viewer
+                return context.models.message.removeQuestion(args.questionToRemove);
+                throw new apollo_server_core_1.AuthenticationError("Not a viewer");
+            });
+        },
+        // Member mutations
+        // @rights member
+        userLeaveGroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isMember(args.gid)) {
+                    return context.models.group.userLeaveGroup(args.gid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a member");
+            });
+        },
+        // @rights member
+        createPrivatePost: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isMember(args.toGroup)) {
+                    return context.models.message.createPrivatePost(args.toGroup, args.title, args.content);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a member");
+            });
+        },
+        // @rights member du groupe et author du post
+        editPrivatePost: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier qu'il est l'auteur du post et member
+                return context.models.message.editPrivatePost(args.privatePostToEdit, args.title, args.content);
+                throw new apollo_server_core_1.AuthenticationError("Not a member");
+            });
+        },
+        // @rights member du groupe et author du post
+        removePrivatePost: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier qu'il est l'auteur du post et member
+                return context.models.message.removePrivatePost(args.privatePostToRemove);
+                throw new apollo_server_core_1.AuthenticationError("Not a member");
+            });
+        },
+        // Speaker mutations
+        // @rights speaker
+        writePostsSummary: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.forGroup)) {
+                    return context.models.group.writePostsSummary(args.forGroup, args.content);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker
+        groupParticipate: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.gid)) {
+                    return context.models.message.groupParticipate(args.gid, args.forEvent);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker
+        groupUnparticipate: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.gid)) {
+                    return context.models.message.groupUnparticipate(args.gid, args.forEvent);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        groupRequestCoauthorEvent: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.fromGroup)) {
+                    return context.models.request.groupRequestCoauthorEvent(args.fromGroup, args.toGroup, args.forEvent, args.comment);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        createAnnouncement: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.fromGroup)) {
+                    return context.models.message.createAnnouncement(args.fromGroup, new tools_1.GroupSet(args.toGroups), args.title, args.content, args.forEvent);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        editAnnouncement: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations.
+                return context.models.message.editAnnouncement(args.announcementToEdit, args.title, args.content, args.forEvent);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        removeAnnouncement: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations
+                return context.models.message.removeAnnouncement(args.announcementToRemove);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        createEvent: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSpeaker(args.fromGroup)) {
+                    return context.models.message.createEvent(args.fromGroup, new tools_1.GroupSet(args.toGroups), args.title, args.content, args.location, args.startTime, args.endTime, args.forAnnouncement);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        editEvent: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations.
+                return context.models.message.editEvent(args.eventToEdit, args.title, args.content, args.location, args.startTime, args.endTime, args.forAnnouncement);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe émetteur
+        removeEvent: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations
+                return context.models.message.removeEvent(args.eventToRemove);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe
+        createAnswer: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations.
+                return context.models.message.createAnswer(args.forQuestion, args.title, args.content);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe
+        editAnswer: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations.
+                return context.models.message.editAnswer(args.answerToEdit, args.title, args.content);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // @rights speaker du groupe
+        removeAnswer: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                // TODO : Vérifier les autorisations
+                return context.models.message.removeAnswer(args.answerToRemove);
+                throw new apollo_server_core_1.AuthenticationError("Not a speaker");
+            });
+        },
+        // Admin mutations
+        // @rights admin of parent group
+        createSubgroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.fromGroup)) {
+                    return context.models.group.createSubgroup(args);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        makeAdmin: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.makeAdmin(args.forGroup, args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        unmakeAdmin: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.unmakeAdmin(args.forGroup, args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        makeSpeaker: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.makeSpeaker(args.forGroup, args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        unmakeSpeaker: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.unmakeSpeaker(args.forGroup, args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        editGroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.editGroup(args);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        addVisibilityEdge: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.addVisibilityEdge(args.forGroup, args.visibleBy);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        removeVisibilityEdge: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.forGroup)) {
+                    return context.models.group.removeVisibilityEdge(args.forGroup, args.visibleBy);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe émetteur
+        groupRequestJoinMetagroup: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.fromGroup)) {
+                    return context.models.request.groupRequestJoinMetagroup(args.fromGroup, args.toMetagroup, args.comment);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        acceptUserJoinRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let req = yield requests_1.UserJoinGroup.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.acceptUserJoinRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        acceptGroupJoinRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let req = yield requests_1.GroupJoinMetagroup.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.acceptGroupJoinRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        refuseUserJoinRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let req = yield requests_1.UserJoinGroup.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.refuseUserJoinRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        refuseGroupJoinRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                let req = yield requests_1.GroupJoinMetagroup.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.refuseGroupJoinRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin
+        removeUser: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isAdmin(args.fromGroup)) {
+                    return context.models.group.removeUser(args.fromGroup, args.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        acceptGroupCoauthorEventRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                // Pour l'instant, ce n'est pas a implémenter...
+                let req = yield requests_1.GroupCoauthorEvent.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.acceptGroupCoauthorEventRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe destinataire
+        refuseGroupCoauthorEventRequest: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                // Pour l'instant, ce n'est pas a implémenter...
+                let req = yield requests_1.GroupCoauthorEvent.tryCreate(args.request);
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                //if (context.models.auth.isAdmin(req.to)) {
+                return context.models.request.refuseGroupCoauthorEventRequest(req, args.comment);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe
+        censorQuestion: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.censorQuestion(args.questionToCensor);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe
+        censorAnswer: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.censorAnswer(args.answerToCensor);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin du groupe
+        censorPrivatePost: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.censorPrivatePost(args.privatePostToCensor);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin d'un groupe author
+        censorAnnouncement: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.censorAnnouncement(args.announcementToCensor);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // @rights admin d'un groupe author
+        censorEvent: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                throw "Not implemented";
+                //TODO : Vérifier les autorisations
+                return context.models.message.censorEvent(args.eventToCensor);
+                throw new apollo_server_core_1.AuthenticationError("Not an admin");
+            });
+        },
+        // Supervisor mutations
+        // @rights supervisor
+        takeAdminRights: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSupervisor(args.forGroup)) {
+                    return context.models.group.takeAdminRights(args.forGroup, context.user.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a supervisor");
+            });
+        },
+        // @rights supervisor
+        releaseAdminRights: function (root, args, context) {
+            return __awaiter(this, void 0, void 0, function* () {
+                if (context.models.auth.isSupervisor(args.forGroup)) {
+                    return context.models.group.releaseAdminRights(args.forGroup, context.user.uid);
+                }
+                throw new apollo_server_core_1.AuthenticationError("Not a supervisor");
+            });
+        }
+    }
+};
+//# sourceMappingURL=resolvers.js.map
\ No newline at end of file
diff --git a/tsbuild/src/graphql/resolvers.js.map b/tsbuild/src/graphql/resolvers.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..3d08a4050da2fb4068cc830e1025427eb3924085
--- /dev/null
+++ b/tsbuild/src/graphql/resolvers.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"resolvers.js","sourceRoot":"","sources":["../../../src/graphql/resolvers.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/index.js b/tsbuild/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e27ff276c4e6c0a1ba35a1ee07f221e5ad3f473
--- /dev/null
+++ b/tsbuild/src/index.js
@@ -0,0 +1,24 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * @file Lance le serveur configuré dans {@link app.ts}
+ * @author manifold
+ */
+const dotenv_1 = __importDefault(require("dotenv")); //loads environment variables from (hidden) .env file into process.env
+dotenv_1.default.config();
+const app_1 = __importDefault(require("./app"));
+const colors_1 = __importDefault(require("colors"));
+const port = process.env.PORT;
+const hostnameConfigMap = {
+    'development': 'localhost',
+    'staging': '0.0.0.0',
+    'production': '0.0.0.0'
+};
+const hostname = process.env.HOST || hostnameConfigMap[process.env.TARGET_ENV];
+app_1.default.listen(port, () => {
+    console.log(colors_1.default.blue("🚀  Server ready on %s:%s."), hostname, port);
+});
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/tsbuild/src/index.js.map b/tsbuild/src/index.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..b6d31beeb912bc114814460508ba833e4ef0c743
--- /dev/null
+++ b/tsbuild/src/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;AAAA;;;GAGG;AACH,oDAA4B,CAAC,sEAAsE;AACnG,gBAAM,CAAC,MAAM,EAAE,CAAC;AAChB,gDAAwB;AACxB,oDAA4B;AAE5B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9B,MAAM,iBAAiB,GAAG;IACtB,aAAa,EAAE,WAAW;IAC1B,SAAS,EAAE,SAAS;IACpB,YAAY,EAAE,SAAS;CAC1B,CAAC;AACF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAE/E,aAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IAClB,OAAO,CAAC,GAAG,CAAC,gBAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC"}
\ No newline at end of file
diff --git a/tsbuild/src/ldap/export/group.js b/tsbuild/src/ldap/export/group.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f3d05aabf2da353bc51615e27115e23c4e0d7c0
--- /dev/null
+++ b/tsbuild/src/ldap/export/group.js
@@ -0,0 +1,337 @@
+"use strict";
+/**
+ * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
+ * @author hawkspar
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const config_1 = require("../internal/config");
+const basics_1 = require("../internal/basics");
+const tools_1 = require("../internal/tools");
+//------------------------------------------------------------------------------------------------------------------------
+// Classes à exporter TBT
+//------------------------------------------------------------------------------------------------------------------------
+class Group {
+    /**
+     * @memberof LDAP
+     * @class Group
+     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les groupes.
+     * @summary Constructeur vide.
+     */
+    constructor() { }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui renvoit toutes les infos relatives à un groupe particulier.
+     * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link groupData}. Elle rajoute les individus
+     * @arg {string} gid - Identifiant du groupe
+     * @return {Promise(groupData)} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe au format {@link groupData}.
+     * @static
+     * @async
+     */
+    static peek(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return tools_1.Tools.peek("group", gid, config_1.groupData);
+            }
+            catch (err) {
+                throw "Erreur lors d'une recherche d'informations sur un groupe.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @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) pour les groupes.
+     * @desc Cette fonction utilise {@link Tools.search}.
+     * @arg {groupData} input - String entré par l'utilisateur qui ressemble au nom du groupe.
+     * @return {Promise(string[])} Liste des gid dont le nom ressemble à l'input.
+     * @static
+     * @async
+    */
+    static search(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return tools_1.Tools.search("group", data);
+            }
+            catch (err) {
+                throw "Erreur lors de la recherche approximative d'un groupe.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de rajouter un administrateur à un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Le nouvel administrateur ne devient pas membre ou porte-parole du groupe pour autant !
+     * @arg {string} uid - Identifiant du membre futur admin
+     * @arg {string} gid - Identifiant du groupe
+     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static addAdmin(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return yield tools_1.Tools.add(uid, gid, "admins"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de supprimer un administrateur.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}.
+     * Elle ne remonte pas les échelons, car cela permettrait à un admin d'un petit groupe de supprimer un admin d'un grand.
+     * @arg {string} uid - Identifiant de l'admin à dégrader, supposé membre
+     * @arg {string} gid - Identifiant du groupe
+     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static remAdmin(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return tools_1.Tools.remove(uid, gid, "admins"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de rajouter un porte-parole à un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}. Elle ne rajoute pas l'utilisateur au groupe.
+     * @arg {string} uid - Identifiant du membre futur porte-parole
+     * @arg {string} gid - Identifiant du groupe
+     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static addSpeaker(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return yield tools_1.Tools.add(uid, gid, "speakers"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de rétrograder un membre du stade de porte-parole d'un groupe au stade d'utilisateur.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.remove}. Elle dégrade aussi d'un éventuel statut d'administrateur.
+     * @arg {string} uid - Identifiant de l'admin à dégrader (pas supposé valide)
+     * @arg {string} gid - Identifiant du groupe
+     * @return {boolean} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static remSpeaker(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return yield tools_1.Tools.remove(uid, gid, "speakers"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet d'ajouter un utilisateur à un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
+     * @arg {string} uid - Identifiant de l'utilisateur à ajouter
+     * @arg {string} gid - Identifiant du groupe
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static addMember(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return tools_1.Tools.add(uid, gid, "members"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de supprimer un membre existant d'un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
+     * Cette fonction supprime tous les droits de l'utilisateur sur le groupe, mais aussi sur les groupes sources si son statut de membre était hérité.
+     * @arg {string} uid - Identifiant de l'ex-membre (pas supposé valide)
+     * @arg {string} gid - Identifiant du groupe
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static remMember(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            return yield tools_1.Tools.remove(uid, gid, "members");
+            // Ce qui suit est une suppression récursive du membre dans tous les groupes fils
+            let stack = [];
+            let res = true;
+            let visited = {};
+            stack.push(gid);
+            while (stack.length > 0) {
+                let cur_id = stack.pop();
+                if (visited[cur_id] == undefined) {
+                    visited[cur_id] = true;
+                    res = res && (yield tools_1.Tools.remove(uid, cur_id, "admins")) &&
+                        (yield tools_1.Tools.remove(uid, cur_id, "speakers")) &&
+                        (yield tools_1.Tools.remove(uid, cur_id, "members"));
+                    stack.concat(yield basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.childs, cur_id));
+                }
+            }
+            return res;
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet d'ajouter un sympathisant à un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
+     * @arg {string} uid - Identifiant de l'utilisateur à ajouter
+     * @arg {string} gid - Identifiant du groupe
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static addFollower(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return tools_1.Tools.add(uid, gid, "followers"); });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de supprimer un sympathisant d'un groupe.
+     * @desc Cette fonction fait essentiellement appel à {@link Tools.add}.
+     * @arg {string} uid - Identifiant de l'ex-sympathisant (pas supposé valide)
+     * @arg {string} gid - Identifiant du groupe
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static remFollower(uid, gid) {
+        return __awaiter(this, void 0, void 0, function* () { return tools_1.Tools.remove(uid, gid, "followers"); });
+    }
+    /**
+     * @memberof LDAP
+     * @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 LDAP.add} et {@link LDAP.change}, mais aussi {@link Tools.add}
+     * pour gérer les groupes du nouvel utilisateur. Cettte application permet de rajouter des utilisateurs à toutes les catégories du groupe.
+     * @arg {groupData} data - Dictionnaire des informations utilisateurs (voir détail des champs dans ldapConfig.json)
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static create(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // Calcul d'un dictionnaire d'ajout
+            let vals = {};
+            // gid de base généré à partir du nom standardisé, pas à partir de l'entrée 'gid' !
+            try {
+                tools_1.Tools.generateReadableId(data['name']).then(id => {
+                    vals[config_1.ldapConfig.key_id] = id;
+                    vals[config_1.ldapConfig.group['name']] = id;
+                });
+            }
+            catch (err) {
+                throw "Erreur lors de la génération d'un hruid pour créer un nouveau groupe.";
+            }
+            let gid = vals[config_1.ldapConfig.key_id];
+            // Ecriture de toutes les valeurs directement inscrites dans le LDAP
+            for (let key_att in data) {
+                vals[config_1.ldapConfig.group[key_att]] = data[key_att];
+            }
+            ;
+            // Appel à la fonction de base
+            if (!(yield basics_1.Basics.add("group", vals))) {
+                throw "Erreur lors de la création d'une nouvelle feuille dans l'arbre des groupes.";
+            }
+            // Certains champs nécessitent de petits calculs
+            let vals2 = {};
+            // ?!
+            vals2[config_1.ldapConfig.group['password']] = "{CRYPT}" + data['password'];
+            // Génération id aléatoire et test contre le LDAP
+            try {
+                tools_1.Tools.generateId(config_1.ldapConfig.group["idNumber"], "group").then(id => { vals2[config_1.ldapConfig.group['idNumber']] = id; });
+            }
+            catch (err) {
+                throw "Erreur lors de la génération d'un id numérique pour créer un nouveau groupe.";
+            }
+            // Code root
+            vals2[config_1.ldapConfig.group['cleanFullName']] = data['name'].replace(':', ';').toLowerCase().normalize('UFD');
+            // Inscription des valeurs calculées par effet de bord
+            if (!(yield basics_1.Basics.change("group", gid, "add", vals2))) {
+                throw "Erreur lors de l'ajout des valeurs intelligentes du nouveau groupe.";
+            }
+            ["posixGroup", "brGroup"].forEach(cst => {
+                let vals3 = {};
+                vals3[config_1.ldapConfig.group['classes']] = cst;
+                basics_1.Basics.change("group", gid, "add", vals3).then(res => {
+                    if (!res) {
+                        throw "Erreur lors de l'ajout des valeurs constantes du nouveau groupe.";
+                    }
+                });
+            });
+            // Utilisation des fonctions adaptées pour assurer la cohérence de l'ensemble
+            for (let cat in config_1.categories) {
+                data[cat].forEach(uid => {
+                    tools_1.Tools.add(uid, gid, cat).then(res => {
+                        if (!res) {
+                            throw "Erreur de l'ajout d'un membre au nouveau groupe.";
+                        }
+                    });
+                });
+            }
+            return true;
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui supprime un groupe du LDAP.
+     * @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement. A modifier une fois que le LDAP incluerait les groupes administres par une utilisateur.
+     * Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} 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
+     * @async
+     * @static
+     */
+    static delete(gid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // Gestion des catégories en bloc d'abord
+                let profil = yield Group.peek(gid);
+                for (let cat of config_1.categories) {
+                    profil[config_1.ldapConfig.group[cat]].forEach(function quickPartRemUser(uid) {
+                        return __awaiter(this, void 0, void 0, function* () {
+                            // Modification des profils de tous les utilisateurs
+                            let lg = yield tools_1.Tools.get(uid, "user", cat);
+                            // Vérifie que l'utilisateur est pas déjà viré pour users
+                            if (lg.includes(gid)) {
+                                // Supprime tous les groupes
+                                if (!(yield basics_1.Basics.change("user", uid, "del", config_1.ldapConfig.user[cat]))) {
+                                    throw "Erreur lors de la suppression de tous les groupes du membre.";
+                                }
+                                // Les rajoute un par un, sauf pour le groupe supprimé
+                                lg.forEach(id => {
+                                    if (id != gid) {
+                                        tools_1.Tools.add(uid, id, cat).then(res => {
+                                            if (!res) {
+                                                throw "Erreur lors du ré-ajout des autres groupes";
+                                            }
+                                        });
+                                    }
+                                });
+                            }
+                        });
+                    });
+                }
+                // Elimination
+                if (!(yield basics_1.Basics.clear("group", gid))) {
+                    throw "Erreur lors de la suppression de la feuille dans l'arbre des groupes.";
+                }
+                return true;
+            }
+            catch (err) {
+                throw "Erreur lors de l'obtention du profil d'un groupe pour le supprimer.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui édite un groupe existant dans le LDAP. Sans influence sur ses membres ou admins.
+     * @desc Appelle {@link Tools.edit}.
+     * @arg {groupData} data - Dictionnaire des informations du groupe.
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static edit(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return tools_1.Tools.edit("group", data);
+            }
+            catch (err) {
+                throw "Erreur lors de la modification d'un groupe.";
+            }
+        });
+    }
+}
+exports.Group = Group;
+//# sourceMappingURL=group.js.map
\ No newline at end of file
diff --git a/tsbuild/src/ldap/export/group.js.map b/tsbuild/src/ldap/export/group.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..4dc5b682fbd53138c1aacb934665ddc2ba4fc347
--- /dev/null
+++ b/tsbuild/src/ldap/export/group.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"group.js","sourceRoot":"","sources":["../../../../src/ldap/export/group.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsbuild/src/ldap/export/user.js b/tsbuild/src/ldap/export/user.js
new file mode 100644
index 0000000000000000000000000000000000000000..900d8818eb42b09a3d1dc74b41365dd4ef19f87f
--- /dev/null
+++ b/tsbuild/src/ldap/export/user.js
@@ -0,0 +1,234 @@
+"use strict";
+/**
+ * @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
+ * @author hawkspar
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const config_1 = require("../internal/config");
+exports.userData = config_1.userData;
+const basics_1 = require("../internal/basics");
+const tools_1 = require("../internal/tools");
+class User {
+    /**
+     * @memberof LDAP
+     * @class User
+     * @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs.
+     * @summary Constructeur vide.
+     */
+    constructor() { }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui renvoit les infos de base relatives à un utilisateur particulier.
+     * @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link userData}.
+     * @arg {string} uid - Identifiant de l'utilisateur, supposé valide.
+     * @return {Promise(userData)} Informations recueillies au format {@link userData}.
+     * @static
+     * @async
+     */
+    static peek(uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                let data = yield tools_1.Tools.peek("user", uid, config_1.userData);
+                for (let cat in config_1.categories) {
+                    data[cat] = yield basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.key_id, "*", config_1.ldapConfig.group[cat] + "=" + uid);
+                }
+                return data;
+            }
+            catch (err) {
+                throw "Error while peeking a user.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui retrouve les uid des paxs validant les critères de recherche. Utiliser {@link User.peek} au cas par cas après pour obtenir les vraies infos.
+     * @desc Cette fonction utilise {@link Tools.search}.
+     * @arg {userData} 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 exemple pour chercher un membre
+     * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
+     * @return {Promise(string[])} gids des profils qui "match" les critères proposés.
+     * @static
+     * @async
+     */
+    static search(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return tools_1.Tools.search("user", data);
+            }
+            catch (err) {
+                throw "Erreur lors de la recherche approximative d'un utilisateur.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui créé un nouvel utilisateur dans le LDAP.
+     * @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Tools.add} pour gérer les groupes du nouvel utilisateur.
+     * @arg {userData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis.
+     * Cette application permet de rejoindre des groupes en masse pour toute catégorie.
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static create(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // 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
+            try {
+                tools_1.Tools.generateUid(data['givenName'], data['lastName'], data['birthdate']).then(id => { vals[config_1.ldapConfig.key_id] = id; });
+            }
+            catch (err) {
+                throw "Erreur lors de la génération d'un hruid pour un nouvel utilisateur.";
+            }
+            let uid = vals[config_1.ldapConfig.key_id];
+            // Génère une erreur si un champ n'est pas rempli
+            for (let key_att in data) {
+                // Ecriture de toutes les valeurs uniques
+                if (!Array.isArray(data[key_att])) {
+                    vals[config_1.ldapConfig.user[key_att]] = data[key_att];
+                }
+            }
+            // Appel à la fonction de base
+            if (!(yield basics_1.Basics.add("user", vals))) {
+                throw "Erreur de l'ajout de la feuille à l'arbre utilisateur.";
+            }
+            for (let key_att in data) {
+                // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples
+                if (Array.isArray(data[key_att])) {
+                    // On rajoute chaque valeur en entrée
+                    data[key_att].forEach(val => {
+                        let vals2 = {};
+                        vals2[config_1.ldapConfig.user[key_att]] = val;
+                        basics_1.Basics.change("user", uid, "add", vals2).then(res => {
+                            if (!res) {
+                                throw "Erreur lors de l'ajout d'une valeur pour un champ à valeurs multiples à la feuille du nouvel utilisateur.";
+                            }
+                        });
+                    });
+                }
+            }
+            // Certains champs nécessitent de petits calculs
+            let vals3 = {};
+            // ldapConfiguration du mot de passe utilisateur
+            // Le préfixe {CRYPT} signifie que le mdp est hashé dans OpenLDAP voir : https://www.openldap.org/doc/admin24/security.html 
+            vals3[config_1.ldapConfig.user['password']] = "{CRYPT}" + data['password'];
+            // Ecriture d'un surnom s'il y a lieu
+            if ((data['nickname'] != undefined) && (data['nickname'] != '')) {
+                vals3[config_1.ldapConfig.user['nickname']] = data['nickname'];
+            }
+            try {
+                // Génération id aléatoire unique
+                vals3[config_1.ldapConfig.user['id']] = yield tools_1.Tools.generateId(config_1.ldapConfig.user['id'], "user");
+            }
+            catch (err) {
+                throw "Erreur lors de la génération d'un id numérique pour un nouvel utilisateur.";
+            }
+            // Code root
+            vals3[config_1.ldapConfig.user['cleanFullName']] = data['fullName'].replace(':', ';').toLowerCase().normalize('UFD');
+            // Inscription des valeurs calculées
+            if (!(yield basics_1.Basics.change("user", uid, "add", vals3))) {
+                throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur.";
+            }
+            ["posixAccount", "shadowAccount", "brUser"].forEach(cst => {
+                let val3 = {};
+                vals3[config_1.ldapConfig.user['class']] = cst;
+                basics_1.Basics.change("user", uid, "add", vals3).then(res => {
+                    if (!res) {
+                        throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur.";
+                    }
+                });
+            });
+            // Ajout dans les groupes à la catégorie voulue
+            for (let cat of config_1.categories) {
+                for (let gid of data[cat]) {
+                    tools_1.Tools.add(uid, gid, cat);
+                }
+            }
+            return true;
+        });
+    }
+    //------------------------------------------------------------------------------------------------------------------------
+    // Fonctions de suppression TBT
+    //------------------------------------------------------------------------------------------------------------------------
+    /**
+     * @memberof LDAP
+     * @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 LDAP.clear} bien sûr, mais aussi {@link Tools.remove} 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
+     * @async
+     * @static
+     */
+    static delete(uid) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // Gestion des groupes d'abord
+                let profil = yield User.peek(uid);
+                for (let cat of config_1.categories) {
+                    profil[config_1.ldapConfig.user[cat]].forEach(function (gid) {
+                        return __awaiter(this, void 0, void 0, function* () {
+                            // Enlever de la liste des membres
+                            let lm = yield tools_1.Tools.get(gid, "group", cat);
+                            if (lm.includes(uid)) {
+                                // Supprime tous les membres
+                                if (!(yield basics_1.Basics.change("group", gid, "del", config_1.ldapConfig.group[cat]))) {
+                                    throw "Erreur lors de la suppression de tous les membres du groupe.";
+                                }
+                                // Les rajoute un par un, sauf pour le supprimé
+                                lm.forEach(id => {
+                                    if (id != uid) {
+                                        tools_1.Tools.add(id, gid, cat).then(res => {
+                                            if (!res) {
+                                                throw "Erreur lors du ré-ajout d'un autre membre";
+                                            }
+                                        });
+                                    }
+                                });
+                            }
+                        });
+                    });
+                }
+            }
+            catch (err) {
+                throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer.";
+            }
+            // Elimination
+            if (!basics_1.Basics.clear("user", uid)) {
+                throw "Erreur lors de la suppression de l'utilisateur.";
+            }
+            return true;
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui édite un utilisateur existant dans le LDAP.
+     * @desc Appelle simplement {@link Tools.edit}. Sans effet sur les groupes de l'utilisateur concerné.
+     * @arg {userData} data - Dictionnaire des informations utilisateurs
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static edit(data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return tools_1.Tools.edit("user", data);
+            }
+            catch (err) {
+                throw "Erreur lors de la modification d'un utilisateur.";
+            }
+        });
+    }
+}
+exports.User = User;
+//# sourceMappingURL=user.js.map
\ No newline at end of file
diff --git a/tsbuild/src/ldap/export/user.js.map b/tsbuild/src/ldap/export/user.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..2a3beece6a5dab3b1a66ad5cb26b820c6fdf5dd6
--- /dev/null
+++ b/tsbuild/src/ldap/export/user.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"user.js","sourceRoot":"","sources":["../../../../src/ldap/export/user.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;AAEH,+CAAoE;AAQ5D,mBARY,iBAAQ,CAQZ;AAPhB,+CAA0C;AAC1C,6CAAwC;AAQxC,MAAa,IAAI;IACb;;;;;OAKG;IACH,gBAAe,CAAC;IAEhB;;;;;;;;OAQG;IACH,MAAM,CAAO,IAAI,CAAC,GAAW;;YACzB,IAAI;gBACA,IAAI,IAAI,GAAc,MAAM,aAAK,CAAC,IAAI,CAAW,MAAM,EAAE,GAAG,EAAE,iBAAQ,CAAC,CAAC;gBACxE,KAAK,IAAI,GAAG,IAAI,mBAAU,EAAE;oBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,eAAM,CAAC,YAAY,CAAC,OAAO,EAAE,mBAAU,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,mBAAU,CAAC,KAAK,CAAC,GAAG,CAAC,GAAC,GAAG,GAAC,GAAG,CAAC,CAAC;iBAAE;gBAC5I,OAAO,IAAI,CAAC;aACf;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,6BAA6B,CAAC;aACvC;QACL,CAAC;KAAA;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAO,MAAM,CAAC,IAAc;;YAC9B,IAAI;gBACA,OAAO,aAAK,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aACrC;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,6DAA6D,CAAC;aACvE;QACL,CAAC;KAAA;IAED;;;;;;;;;OASG;IACH,MAAM,CAAO,MAAM,CAAC,IAAc;;YAC9B,mCAAmC;YACnC,IAAI,IAAI,GAAG,EAAE,CAAC;YAEd,wFAAwF;YACxF,iDAAiD;YACjD,IAAI;gBACA,aAAK,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,EAAC,IAAI,CAAC,UAAU,CAAC,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,mBAAU,CAAC,MAAM,CAAC,GAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC;aACxH;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,qEAAqE,CAAC;aAC/E;YAED,IAAI,GAAG,GAAG,IAAI,CAAC,mBAAU,CAAC,MAAM,CAAC,CAAC;YAElC,iDAAiD;YACjD,KAAK,IAAI,OAAO,IAAI,IAAI,EAAE;gBACtB,yCAAyC;gBACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;oBAAE,IAAI,CAAC,mBAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAC,IAAI,CAAC,OAAO,CAAC,CAAC;iBAAE;aACvF;YAED,8BAA8B;YAC9B,IAAI,CAAC,CAAA,MAAM,eAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA,EAAE;gBAAE,MAAM,wDAAwD,CAAC;aAAE;YAExG,KAAK,IAAI,OAAO,IAAI,IAAI,EAAE;gBACtB,wGAAwG;gBACxG,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;oBAC9B,qCAAqC;oBACrC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;wBACxB,IAAI,KAAK,GAAG,EAAE,CAAC;wBACf,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAC,GAAG,CAAC;wBACpC,eAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;4BAChD,IAAI,CAAC,GAAG,EAAE;gCAAE,MAAM,2GAA2G,CAAC;6BAAE;wBACpI,CAAC,CAAC,CAAC;oBACP,CAAC,CAAC,CAAC;iBACN;aACJ;YAED,gDAAgD;YAChD,IAAI,KAAK,GAAC,EAAE,CAAC;YAEb,gDAAgD;YAChD,4HAA4H;YAC5H,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,SAAS,GAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAEhE,qCAAqC;YACrC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAE,EAAE,CAAC,EAAE;gBACzD,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAC,IAAI,CAAC,UAAU,CAAC,CAAC;aACvD;YACD,IAAI;gBACA,iCAAiC;gBACjC,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAE,MAAM,aAAK,CAAC,UAAU,CAAC,mBAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;aACvF;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,4EAA4E,CAAC;aACtF;YAED,YAAY;YACZ,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAE1G,oCAAoC;YACpC,IAAI,CAAC,CAAA,MAAM,eAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA,EAAE;gBACjD,MAAM,kFAAkF,CAAC;aAC5F;YAED,CAAC,cAAc,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBACtD,IAAI,IAAI,GAAC,EAAE,CAAC;gBACZ,KAAK,CAAC,mBAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAC,GAAG,CAAC;gBACpC,eAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;oBAChD,IAAI,CAAC,GAAG,EAAE;wBAAE,MAAM,mFAAmF,CAAC;qBAAE;gBAC5G,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,+CAA+C;YAC/C,KAAK,IAAI,GAAG,IAAI,mBAAU,EAAE;gBACxB,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE;oBACvB,aAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;iBAC5B;aACJ;YACD,OAAO,IAAI,CAAC;QAChB,CAAC;KAAA;IAED,0HAA0H;IAC1H,+BAA+B;IAC/B,0HAA0H;IAE1H;;;;;;;;;OASG;IACH,MAAM,CAAO,MAAM,CAAC,GAAW;;YAC3B,IAAI;gBACA,8BAA8B;gBAC9B,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAClC,KAAK,IAAI,GAAG,IAAI,mBAAU,EAAE;oBACxB,MAAM,CAAC,mBAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,UAAgB,GAAW;;4BAC5D,kCAAkC;4BAClC,IAAI,EAAE,GAAG,MAAM,aAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;4BAC5C,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gCAClB,4BAA4B;gCAC5B,IAAI,CAAC,CAAA,MAAM,eAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,mBAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA,EAAE;oCAClE,MAAM,8DAA8D,CAAC;iCACxE;gCACD,+CAA+C;gCAC/C,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;oCACZ,IAAI,EAAE,IAAE,GAAG,EAAE;wCACT,aAAK,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;4CAC/B,IAAI,CAAC,GAAG,EAAE;gDAAE,MAAM,2CAA2C,CAAC;6CAAE;wCACpE,CAAC,CAAC,CAAC;qCACN;gCACL,CAAC,CAAC,CAAC;6BACN;wBACL,CAAC;qBAAA,CAAC,CAAC;iBACN;aACJ;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,2EAA2E,CAAC;aACrF;YACD,cAAc;YACd,IAAI,CAAC,eAAM,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;gBAAE,MAAM,iDAAiD,CAAC;aAAE;YAC5F,OAAO,IAAI,CAAC;QAChB,CAAC;KAAA;IAED;;;;;;;;OAQG;IACH,MAAM,CAAO,IAAI,CAAC,IAAe;;YAC7B,IAAI;gBACA,OAAO,aAAK,CAAC,IAAI,CAAC,MAAM,EAAC,IAAI,CAAC,CAAC;aAClC;YACD,OAAM,GAAG,EAAE;gBACP,MAAM,kDAAkD,CAAC;aAC5D;QACL,CAAC;KAAA;CACJ;AA7MD,oBA6MC"}
\ No newline at end of file
diff --git a/src/ldap/internal/basics.js b/tsbuild/src/ldap/internal/basics.js
similarity index 56%
rename from src/ldap/internal/basics.js
rename to tsbuild/src/ldap/internal/basics.js
index a0a80e3ad605806fdc91bdee8daafdcfff7130ed..db06c5156439d2bb22d800d096fbad8ca7c73cf4 100644
--- a/src/ldap/internal/basics.js
+++ b/tsbuild/src/ldap/internal/basics.js
@@ -14,53 +14,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
         step((generator = generator.apply(thisArg, _arguments || [])).next());
     });
 };
-var __generator = (this && this.__generator) || function (thisArg, body) {
-    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
-    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
-    function verb(n) { return function (v) { return step([n, v]); }; }
-    function step(op) {
-        if (f) throw new TypeError("Generator is already executing.");
-        while (_) try {
-            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
-            if (y = 0, t) op = [0, t.value];
-            switch (op[0]) {
-                case 0: case 1: t = op; break;
-                case 4: _.label++; return { value: op[1], done: false };
-                case 5: _.label++; y = op[1]; op = [0]; continue;
-                case 7: op = _.ops.pop(); _.trys.pop(); continue;
-                default:
-                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
-                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
-                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
-                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
-                    if (t[2]) _.ops.pop();
-                    _.trys.pop(); continue;
-            }
-            op = body.call(thisArg, _);
-        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
-        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
-    }
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
 };
-exports.__esModule = true;
-var ldapjs_1 = require("ldapjs");
+Object.defineProperty(exports, "__esModule", { value: true });
+const ldapjs_1 = __importDefault(require("ldapjs"));
 // Toutes les entrées utilisateur sont escapées par sécurité
-var ldap_escape_1 = require("ldap-escape");
+const ldap_escape_1 = __importDefault(require("ldap-escape"));
 // Fichier de ldapConfig du ldap
-var config_1 = require("./config");
+const config_1 = require("./config");
 // Connection au serveur LDAP avec des temps de timeout arbitraires
-var client = ldapjs_1["default"].createClient({ url: config_1.ldapConfig.server });
+var client = ldapjs_1.default.createClient({ url: config_1.ldapConfig.server });
 //------------------------------------------------------------------------------------------------------------------------
 // Fonctions de base agissant sur le LDAP
 //------------------------------------------------------------------------------------------------------------------------
-var Basics = /** @class */ (function () {
+class Basics {
     /**
      * @class Basics
      * @classdesc Cette classe est la brique de base du fichier tout entier puisqu'elle contient les functions qui agissent directement sur le LDAP.
      * @memberof LDAP
      * @summary Constructeur vide.
      */
-    function Basics() {
-    }
+    constructor() { }
     /**
      * @memberof LDAP
      * @summary Fonction qui sert à s'identifier sur le LDAP.
@@ -72,24 +47,22 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.bind = function (dn, password) {
-        return __awaiter(this, void 0, void 0, function () {
-            return __generator(this, function (_a) {
-                // Escape DN as everywhere in this file, but password is taken as is
-                client.bind(dn, password, function (res) {
-                    // Gestion erreur
-                    try {
-                        res;
-                    }
-                    catch (err) {
-                        throw "Erreur lors de la connection au LDAP.";
-                    }
-                });
-                // End with a boolean
-                return [2 /*return*/, true];
+    static bind(dn, password) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // Escape DN as everywhere in this file, but password is taken as is
+            client.bind(dn, password, res => {
+                // Gestion erreur
+                try {
+                    res;
+                }
+                catch (err) {
+                    throw "Erreur lors de la connection au LDAP.";
+                }
             });
+            // End with a boolean
+            return true;
         });
-    };
+    }
     /**
      * @memberof LDAP
      * @summary Fonction qui sert à s'identifier sur le LDAP avec plein pouvoirs.
@@ -98,11 +71,9 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.adminBind = function () {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, Basics.bind(config_1.credentialsLdapConfig.dn, config_1.credentialsLdapConfig.password)];
-        }); });
-    };
+    static adminBind() {
+        return __awaiter(this, void 0, void 0, function* () { return Basics.bind(config_1.credentialsLdapConfig.dn, config_1.credentialsLdapConfig.password); });
+    }
     /**
      * @memberof LDAP
      * @summary Fonction qui sert à se déconnecter du LDAP.
@@ -112,11 +83,9 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.unbind = function () {
-        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
-            return [2 /*return*/, Basics.bind("", "")];
-        }); });
-    };
+    static unbind() {
+        return __awaiter(this, void 0, void 0, function* () { return Basics.bind("", ""); });
+    }
     /**
      * @callback entryHandler
      * @arg entry {*} - Convoluted ldap.js search result object
@@ -135,36 +104,36 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.search = function (domain, attributes, id, filter, handler) {
+    static search(domain, attributes, id, filter, handler) {
         Basics.adminBind();
-        var dn = "";
+        let dn = "";
         if (id != null) {
-            dn += config_1.ldapConfig.key_id + '=' + ldap_escape_1["default"].dn("${txt}", { txt: id }) + ',';
+            dn += config_1.ldapConfig.key_id + '=' + ldap_escape_1.default.dn("${txt}", { txt: id }) + ',';
         }
         dn += config_1.ldapConfig.dn[domain];
         // Interrogation LDAP selon filter
-        var promise = new Promise(function (resolve, reject) {
+        let promise = new Promise(function (resolve, reject) {
             client.search(dn, {
                 "scope": "sub",
                 "filter": filter,
                 "attributes": attributes
-            }, function (err, res) {
+            }, (err, res) => {
                 // Gestion erreur ; pb car pas simple true / autre en sortie
                 if (err) {
                     throw "Erreur lors de la recherche sur le LDAP.";
                 }
                 else {
                     // Dès que la recherche renvoit une entrée, on stocke les attributs qui nous intéresse
-                    res.on('searchEntry', function (entry) { handler(entry); });
+                    res.on('searchEntry', entry => { handler(entry); });
                     // Si la recherche renvoie une erreur, on renvoit
-                    res.on('error', function (resErr) { throw resErr; });
+                    res.on('error', resErr => { throw resErr; });
                     // Quand la recherche est finie on se déconnecte
-                    res.on('end', function (_) { Basics.unbind(); resolve(); });
+                    res.on('end', _ => { Basics.unbind(); resolve(); });
                 }
             });
         });
         return promise;
-    };
+    }
     /**
      * @memberof LDAP
      * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit une liste de valeurs trouvées.
@@ -178,26 +147,16 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.searchSingle = function (domain, attribute, id, filter) {
-        if (id === void 0) { id = null; }
-        if (filter === void 0) { filter = "(objectClass=*)"; }
-        return __awaiter(this, void 0, void 0, function () {
-            var vals;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        vals = [];
-                        return [4 /*yield*/, Basics.search(domain, [attribute], id, filter, function (entry) {
-                                // Cas un seul attribut où le résultat est une liste directement
-                                vals.push(entry.object[attribute]);
-                            })];
-                    case 1:
-                        _a.sent();
-                        return [2 /*return*/, vals];
-                }
+    static searchSingle(domain, attribute, id = null, filter = "(objectClass=*)") {
+        return __awaiter(this, void 0, void 0, function* () {
+            let vals = [];
+            yield Basics.search(domain, [attribute], id, filter, entry => {
+                // Cas un seul attribut où le résultat est une liste directement
+                vals.push(entry.object[attribute]);
             });
+            return vals;
         });
-    };
+    }
     /**
      * @memberof LDAP
      * @summary Fonction qui interroge le LDAP selon un protocole spécifié en argument et renvoit les valeurs trouvées.
@@ -212,29 +171,19 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.searchMultiple = function (domain, attributes, id, filter) {
-        if (id === void 0) { id = null; }
-        if (filter === void 0) { filter = "(objectClass=*)"; }
-        return __awaiter(this, void 0, void 0, function () {
-            var vals;
-            return __generator(this, function (_a) {
-                switch (_a.label) {
-                    case 0:
-                        vals = [];
-                        return [4 /*yield*/, Basics.search(domain, attributes, id, filter, function (entry) {
-                                // Cas plusieurs attributs donc résultat dictionnaire
-                                vals.push({});
-                                attributes.forEach(function (attribute) {
-                                    vals.slice(-1)[0][attribute] = entry.object[attribute];
-                                });
-                            })];
-                    case 1:
-                        _a.sent();
-                        return [2 /*return*/, vals];
-                }
+    static searchMultiple(domain, attributes, id = null, filter = "(objectClass=*)") {
+        return __awaiter(this, void 0, void 0, function* () {
+            let vals = [];
+            yield Basics.search(domain, attributes, id, filter, entry => {
+                // Cas plusieurs attributs donc résultat dictionnaire
+                vals.push({});
+                attributes.forEach(attribute => {
+                    vals.slice(-1)[0][attribute] = entry.object[attribute];
+                });
             });
+            return vals;
         });
-    };
+    }
     //TBT
     /**
      * @memberof LDAP
@@ -250,25 +199,22 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.change = function (domain, id, op, mod) {
-        return __awaiter(this, void 0, void 0, function () {
-            var dn;
-            return __generator(this, function (_a) {
-                Basics.adminBind();
-                dn = config_1.ldapConfig.key_id + '=' + id + ',';
-                dn += config_1.ldapConfig.dn[domain];
-                // Modification LDAP selon dn fourni en argument (pourrait prendre une liste de Changes)
-                client.modify(ldap_escape_1["default"].dn("${txt}", { txt: dn }), new ldapjs_1["default"].Change({
-                    operation: op,
-                    modification: mod
-                }), function (err) {
-                    throw "Erreur lors d'une opération de modification sur le LDAP.";
-                });
-                Basics.unbind();
-                return [2 /*return*/, true];
+    static change(domain, id, op, mod) {
+        return __awaiter(this, void 0, void 0, function* () {
+            Basics.adminBind();
+            let dn = config_1.ldapConfig.key_id + '=' + id + ',';
+            dn += config_1.ldapConfig.dn[domain];
+            // Modification LDAP selon dn fourni en argument (pourrait prendre une liste de Changes)
+            client.modify(ldap_escape_1.default.dn("${txt}", { txt: dn }), new ldapjs_1.default.Change({
+                operation: op,
+                modification: mod,
+            }), err => {
+                throw "Erreur lors d'une opération de modification sur le LDAP.";
             });
+            Basics.unbind();
+            return true;
         });
-    };
+    }
     //TBT
     /**
      * @memberof LDAP
@@ -281,22 +227,19 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.add = function (domain, vals) {
-        return __awaiter(this, void 0, void 0, function () {
-            var dn;
-            return __generator(this, function (_a) {
-                Basics.adminBind();
-                dn = config_1.ldapConfig.key_id + "=" + vals[config_1.ldapConfig.key_id];
-                dn += config_1.ldapConfig.dn[domain];
-                // Ajout LDAP selon la ldapConfiguration en argument
-                client.add(ldap_escape_1["default"].dn("${txt}", { txt: dn }), vals, function (err) {
-                    throw "Erreur lors d'une opération d'ajout sur le LDAP.";
-                });
-                Basics.unbind();
-                return [2 /*return*/, true];
+    static add(domain, vals) {
+        return __awaiter(this, void 0, void 0, function* () {
+            Basics.adminBind();
+            let dn = config_1.ldapConfig.key_id + "=" + vals[config_1.ldapConfig.key_id];
+            dn += config_1.ldapConfig.dn[domain];
+            // Ajout LDAP selon la ldapConfiguration en argument
+            client.add(ldap_escape_1.default.dn("${txt}", { txt: dn }), vals, err => {
+                throw "Erreur lors d'une opération d'ajout sur le LDAP.";
             });
+            Basics.unbind();
+            return true;
         });
-    };
+    }
     //TBT
     /**
      * @memberof LDAP
@@ -309,22 +252,19 @@ var Basics = /** @class */ (function () {
      * @static
      * @async
      */
-    Basics.clear = function (domain, id) {
-        return __awaiter(this, void 0, void 0, function () {
-            var dn;
-            return __generator(this, function (_a) {
-                Basics.adminBind();
-                dn = config_1.ldapConfig.key_id + '=' + id + ',';
-                dn += config_1.ldapConfig.dn[domain];
-                // Suppression LDAP
-                client.del(ldap_escape_1["default"].dn("${txt}", { txt: dn }), function (err) {
-                    throw "Erreur lors d'une opération de suppression sur le LDAP.";
-                });
-                Basics.unbind();
-                return [2 /*return*/, true];
+    static clear(domain, id) {
+        return __awaiter(this, void 0, void 0, function* () {
+            Basics.adminBind();
+            let dn = config_1.ldapConfig.key_id + '=' + id + ',';
+            dn += config_1.ldapConfig.dn[domain];
+            // Suppression LDAP
+            client.del(ldap_escape_1.default.dn("${txt}", { txt: dn }), err => {
+                throw "Erreur lors d'une opération de suppression sur le LDAP.";
             });
+            Basics.unbind();
+            return true;
         });
-    };
-    return Basics;
-}());
+    }
+}
 exports.Basics = Basics;
+//# sourceMappingURL=basics.js.map
\ No newline at end of file
diff --git a/tsbuild/src/ldap/internal/basics.js.map b/tsbuild/src/ldap/internal/basics.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..ad889f7d95586127408d69a598e8ec7fb1886892
--- /dev/null
+++ b/tsbuild/src/ldap/internal/basics.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"basics.js","sourceRoot":"","sources":["../../../../src/ldap/internal/basics.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/src/ldap/internal/config.js b/tsbuild/src/ldap/internal/config.js
similarity index 71%
rename from src/ldap/internal/config.js
rename to tsbuild/src/ldap/internal/config.js
index 41d8b531ee6ae4d02523b8ea2120caecc372aebe..e2dcaea420ff7711d36d293940dcd8e5f733da47 100644
--- a/src/ldap/internal/config.js
+++ b/tsbuild/src/ldap/internal/config.js
@@ -6,22 +6,25 @@
  * @memberof LDAP
  * @author manifold, hawkspar
  */
-exports.__esModule = true;
-var fs_1 = require("fs");
-var path_1 = require("path");
-var colors_1 = require("colors");
-var dotenv_1 = require("dotenv");
-dotenv_1["default"].config();
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const fs_1 = __importDefault(require("fs"));
+const path_1 = __importDefault(require("path"));
+const colors_1 = __importDefault(require("colors"));
+const dotenv_1 = __importDefault(require("dotenv"));
+dotenv_1.default.config({ path: path_1.default.resolve("/" + __dirname, '..', '..', '..', './.env') });
 // Point central ; tous les champs de la BDD sont 'cachés' dans config.json et pas visibles directement
-var path_config = path_1["default"].resolve(__dirname, '..', '..', '..', 'ldap_config.json');
-console.log(colors_1["default"].cyan("Loading LDAP config file from " + path_config));
-exports.ldapConfig = JSON.parse(fs_1["default"].readFileSync(path_config).toString());
+let path_config = path_1.default.resolve("/" + __dirname, '..', '..', '..', '..', './ldap_config.json');
+console.log(colors_1.default.cyan("Loading LDAP config file from " + path_config));
+exports.ldapConfig = JSON.parse(fs_1.default.readFileSync(path_config).toString());
 // Override config server from environment
 if (process.env.LDAP_URI != null) {
     exports.ldapConfig.server = process.env.LDAP_URI;
 }
 else {
-    if (process.env.TARGET_ENV == "production") {
+    if (process.env.TARGET_ENV == `production`) {
         exports.ldapConfig.server = exports.ldapConfig.server_prod;
     }
     else {
@@ -29,9 +32,9 @@ else {
     }
 }
 // Gestion des super-identifiants
-var path_credentials = path_1["default"].resolve(__dirname, '..', '..', '..', 'ldap_credentials.json');
-console.log(colors_1["default"].cyan("Loading LDAP credentials from " + path_credentials));
-exports.credentialsLdapConfig = JSON.parse(fs_1["default"].readFileSync(path_credentials).toString());
+let path_credentials = path_1.default.resolve(__dirname, '..', '..', '..', '..', 'ldap_credentials.json');
+console.log(colors_1.default.cyan("Loading LDAP credentials from " + path_credentials));
+exports.credentialsLdapConfig = JSON.parse(fs_1.default.readFileSync(path_credentials).toString());
 // Data formats and useful constants
 exports.categories = ["admins", "speakers", "members", "followers"];
 /**
@@ -55,11 +58,8 @@ exports.categories = ["admins", "speakers", "members", "followers"];
  * @var {string[]?} followers - Liste des gid dont l'utilisateur est sympathisant
  * @memberof LDAP
  */
-var userData = /** @class */ (function () {
-    function userData() {
-    }
-    return userData;
-}());
+class userData {
+}
 exports.userData = userData;
 /**
  * @class groupData
@@ -78,9 +78,7 @@ exports.userData = userData;
  * @var {string[]} followers - Liste des sympathisants du groupe
  * @memberof LDAP
  */
-var groupData = /** @class */ (function () {
-    function groupData() {
-    }
-    return groupData;
-}());
+class groupData {
+}
 exports.groupData = groupData;
+//# sourceMappingURL=config.js.map
\ No newline at end of file
diff --git a/tsbuild/src/ldap/internal/config.js.map b/tsbuild/src/ldap/internal/config.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..2922c6a3d91573ac8d869fbbbc5af98012af7dd0
--- /dev/null
+++ b/tsbuild/src/ldap/internal/config.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/ldap/internal/config.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;AAEH,4CAAoB;AACpB,gDAAwB;AACxB,oDAA4B;AAC5B,oDAA4B;AAC5B,gBAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,cAAI,CAAC,OAAO,CAAC,GAAG,GAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;AAEjF,uGAAuG;AACvG,IAAI,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,GAAG,GAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC;AACtF,OAAO,CAAC,GAAG,CAAC,gBAAM,CAAC,IAAI,CAAC,gCAAgC,GAAC,WAAW,CAAC,CAAC,CAAC;AAC1D,QAAA,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE9E,0CAA0C;AAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,EAAE;IAC9B,kBAAU,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;CAC5C;KACI;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,YAAY,EAAM;QAAE,kBAAU,CAAC,MAAM,GAAG,kBAAU,CAAC,WAAW,CAAC;KAAE;SAC/C;QAAE,kBAAU,CAAC,MAAM,GAAG,kBAAU,CAAC,UAAU,CAAC;KAAE;CACjG;AAED,iCAAiC;AACjC,IAAI,gBAAgB,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,uBAAuB,CAAC,CAAC;AAC1F,OAAO,CAAC,GAAG,CAAC,gBAAM,CAAC,IAAI,CAAC,gCAAgC,GAAC,gBAAgB,CAAC,CAAC,CAAC;AAC/D,QAAA,qBAAqB,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE9F,oCAAoC;AACvB,QAAA,UAAU,GAAG,CAAC,QAAQ,EAAC,UAAU,EAAC,SAAS,EAAC,WAAW,CAAC,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAa,QAAQ;CAiBpB;AAjBD,4BAiBC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,SAAS;CAcrB;AAdD,8BAcC"}
\ No newline at end of file
diff --git a/tsbuild/src/ldap/internal/tools.js b/tsbuild/src/ldap/internal/tools.js
new file mode 100644
index 0000000000000000000000000000000000000000..d41d09779c089abc6b2aaad5609c4fd552143f53
--- /dev/null
+++ b/tsbuild/src/ldap/internal/tools.js
@@ -0,0 +1,422 @@
+"use strict";
+/**
+ * @file Ce fichier regroupe les fonctions génériques de recherche et de test utiles, mais trop puissantes pour être exportées directement.
+ * @author hawkspar
+ */
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+// Toutes les entrées utilisateur sont escapées par sécurité
+const ldap_escape_1 = __importDefault(require("ldap-escape"));
+// Imports internes
+const config_1 = require("./config");
+const basics_1 = require("./basics");
+//------------------------------------------------------------------------------------------------------------------------
+// Fonctions intermédiaires TBT
+//------------------------------------------------------------------------------------------------------------------------
+class Tools {
+    /**
+     * @memberof LDAP
+     * @class Tools
+     * @classdesc Cette classe contient des fonctions intermédiaires qui ne sont pas destinées à être utilisées dans les resolvers.
+     * @summary Constructeur vide.
+     */
+    constructor() { }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui renvoit toutes les infos relatives à un groupe ou un utilisateur particulier.
+     * @desc Cette fonction utilise {@link LDAP.search} avec des attributs prédéfinis. Elle est naïve et n'opère pas de récursion.
+     * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData})
+     * @arg {string} domain - Domaine de la recherche (utilisateur ou groupe)
+     * @arg {string} id - Identifiant de la feuille cherchée (uid ou gid)
+     * @return {Promise(T)} Informations recueillies ; renvoie une liste de dictionnaire avec le profil complet du groupe tel que défini par le paramètre T.
+     * @static
+     * @async
+     */
+    static peek(domain, id, type) {
+        return __awaiter(this, void 0, void 0, function* () {
+            var dirtyKeys = config_1.ldapConfig[domain];
+            let cleanData = new type();
+            let attr = Object.keys(dirtyKeys).map(key => dirtyKeys[key]);
+            //console.log(attr);
+            let dirtyData = (yield basics_1.Basics.searchMultiple(domain, attr, id))[0];
+            console.log(dirtyData);
+            console.log(cleanData);
+            // Rename output
+            for (let uncleanKey in dirtyData) {
+                for (let cleanKey of Object.keys(cleanData)) {
+                    console.log(cleanKey);
+                    if (uncleanKey == dirtyKeys[cleanKey]) {
+                        cleanData[cleanKey] = dirtyData[uncleanKey];
+                    }
+                }
+            }
+            return cleanData;
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui retrouve les id des paxs ou groupes validant les critères de recherche. Etape vers vrai TOL (Trombino On Line).
+     * Utiliser {@link peekUser} au cas par cas après pour obtenir les vraies infos.
+     * @desc Cette fonction utilise {@link LDAP.search} 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. Va crasher si un champ n'est pas dans ldapConfig.
+     * @param T - Format renvoyé (en pratique {@link userData} ou {@link groupData})
+     * @arg {"us"|"gr"} domain - Domaine de la recherche (utilisateur ou groupe)
+     * @arg {userData | groupData} 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 exemple pour chercher un membre
+     * de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
+     * @return {Promise(string[])} ids des profils qui "match" les critères proposés.
+     * @static
+     * @async
+     */
+    static search(domain, data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let filter = "";
+            // Iteration pour chaque champ, alourdissement du filtre selon des trucs prédéfinis dans ldapConfig 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]];
+                    } // Génération systématique d'une liste de valeurs à rechercher
+                    // Iteration pour chaque valeur fournie par l'utilisateur
+                    data[key].forEach(val => {
+                        // Traduction en language LDAP
+                        let attribute = "";
+                        attribute = config_1.ldapConfig[domain][key];
+                        // Escape user input
+                        val = ldap_escape_1.default.filter("${fil}", { fil: val });
+                        // Creation incrémentale du filtre
+                        filter = "(&" + filter + "(|(" + attribute + "=" + val + ")" + // On cherche la valeur exacte
+                            "(" + attribute + "=*" + val + ")" + // La valeur finale avec des trucs avant ; wildcard * (MEF la wildcart ne marche pas pour tous les attributs)
+                            "(" + attribute + "=*" + val + "*)" + // La valeur du milieu avec des trucs avant et après
+                            "(" + attribute + "=" + val + "*)))"; // La valeur du début avec des trucs après
+                    });
+                }
+            }
+            // Appel avec filtre de l'espace 
+            return basics_1.Basics.searchSingle(domain, config_1.ldapConfig.key_id, null, filter);
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui édite un groupe ou utilisateur existant dans le LDAP. N'agit pas sur l'apprtenance à un groupe.
+     * @desc Appelle {@link LDAP.change}.
+     * @arg {"us"|"gr"} domain - Domaine de l'opération' (utilisateur ou groupe).
+     * @arg {userData | groupData} data - Dictionnaire avec les nouvelles valeurs de la feuille.
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon.
+     * @async
+     * @static
+     */
+    static edit(domain, data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            if (domain == "user") {
+                var id = data['uid'];
+            }
+            else {
+                var id = data['gid'];
+            }
+            var dirtyKeys = config_1.ldapConfig[domain];
+            // Rename in an LDAP-friendly way
+            let dirtyData = {};
+            Object.keys(data).forEach(function (key) {
+                // Some values edit can't change
+                if (!['readPerm', 'writePerm', 'groups', 'groupsIsAdmin', 'followers', 'members', 'speakers', 'admins'].includes(key)) {
+                    dirtyData[dirtyKeys.key] = data[key];
+                }
+            });
+            return basics_1.Basics.change(domain, id, "replace", dirtyData);
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet d'ajouter un utilisateur à une catégorie  d'un groupe.
+     * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}.
+     * Cette fonction ne créé pas de doublon et opère conjointement dans les deux arbres "group" et "user"
+     * @arg {string} uid - Identifiant du futur membre
+     * @arg {string} gid - Identifiant du groupe
+     * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower)
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static add(uid, gid, category) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // Vérifie que l'utilisateur est pas déjà membre pour groupes
+                let lu = yield Tools.get(gid, "group", category);
+                let catName = config_1.ldapConfig.group[category];
+                if (!lu.includes(uid)) {
+                    // Ajoute l'utilisateur dans la catégorie concernée
+                    if (!(yield basics_1.Basics.change("group", gid, "add", catName))) {
+                        throw "Erreur lors de la modification dans l'arbre des groupes pour ajouter un membre dans la catégorie voulue.";
+                    }
+                }
+            }
+            catch (err) {
+                throw "Erreur pour obtenir une liste de membres d'une catégorie d'un groupe pour ajouter un membre de cette categorie du groupe.";
+            }
+            try {
+                // Vérifie que l'utilisateur est pas déjà membre pour user
+                let lg = yield Tools.get(uid, "user", category);
+                let catName = config_1.ldapConfig.user[category];
+                if (!lg.includes(gid)) {
+                    // Ajoute l'utilisateur dans la categorie voulue
+                    if (!(yield basics_1.Basics.change("user", uid, "add", catName))) {
+                        throw "Erreur lors de l'ajout d'un utilisateur dans une catégorie d'un groupe.";
+                    }
+                }
+                return true;
+            }
+            catch (err) {
+                throw "Erreur pour obtenir une liste de groupes d'une categorie d'un membre pour ajouter un groupe de cette category pour le membre.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui permet de supprimer un membre d'une catégorie existant d'un groupe.
+     * @desc Cette fonction fait essentiellement appel à d'autres fonctions de {@link Tools} passées en argument et {@link LDAP.change}.
+     * @arg {string} uid - Identifiant de l'ex-membre
+     * @arg {string} gid - Identifiant du groupe
+     * @arg {"admins"|"speakers"|"members"|"followers"} category - Categorie de l'utilisateur concerné (admin, speaker, member ou follower)
+     * @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
+     * @async
+     * @static
+     */
+    static remove(uid, gid, category) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // Vérifie que l'utilisateur est pas déjà viré pour groupes
+                let lu = yield Tools.get(gid, "group", category);
+                let catName = config_1.ldapConfig.group[category];
+                if (lu.includes(uid)) {
+                    // Supprime tous les utilisateurs
+                    if (!(yield basics_1.Basics.change("group", gid, "del", catName))) {
+                        throw "Erreur lors de la suppression de tous les membres d'une catégorie du groupe.";
+                    }
+                    // Les rajoute un par un, sauf pour le supprimé
+                    lu.forEach(id => {
+                        if (id != uid) {
+                            Tools.add(id, gid, category).then(res => {
+                                if (!res) {
+                                    throw "Erreur lors du ré-ajout d'un autre membre d'une catégorie.";
+                                }
+                            });
+                        }
+                    });
+                }
+            }
+            catch (err) {
+                throw "Erreur pour obtenir une liste de membres d'une catégorie d'un groupe pour supprimer un membre de cette categorie du groupe.";
+            }
+            try {
+                // Vérifie que l'utilisateur est pas déjà viré pour user
+                let lg = yield Tools.get(uid, "user", category);
+                let catName = config_1.ldapConfig.user[category];
+                if (lg.includes(gid)) {
+                    // Supprime tous les groupes de la catégorie pour l'utilisateur
+                    if (!(yield basics_1.Basics.change("user", uid, "del", catName))) {
+                        throw "Erreur lors de la suppression de tous les groupes d'un membre.";
+                    }
+                    // Les rajoute un par un, sauf pour le supprimé
+                    lg.forEach(id => {
+                        if (id != uid) {
+                            Tools.add(id, gid, category).then(res => {
+                                if (!res) {
+                                    throw "Erreur lors du ré-ajout d'un autre groupe.";
+                                }
+                            });
+                        }
+                    });
+                }
+                return true;
+            }
+            catch (err) {
+                throw "Erreur pour obtenir une liste de groupes d'une categorie d'un membre pour supprimer un groupe de cette category pour le membre.";
+            }
+        });
+    }
+    /**
+     * @callback changeValueCallback
+     * @param {string} id - Id à modifier
+     * @param {number} n - Nombre d'itérations
+     * @return {string} Nouveau id
+     */
+    /**
+     * @memberof LDAP
+     * @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.search} pour vérifier
+     * qu'il n'y a pas d'autres occurences de cette valeur pour cette attribut
+     * dans le dn fourni.
+     * @param {string} value - Valeur de l'attribut (le plus souvent un identifiant) à tester à cette itération
+     * @param {string} attribute - Attribut à tester
+     * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique
+     * @param {changeValueCallback} changeValue - 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 {number} n [0] - Nombre d'itérations (à initialiser à 0)
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     * @async
+     */
+    static ensureUnique(value, attribute, domain, changeValue, n = 0) {
+        return __awaiter(this, void 0, void 0, function* () {
+            // Recherche d'autres occurences de l'id
+            try {
+                return basics_1.Basics.searchSingle(domain, config_1.ldapConfig.key_id, null, "(" + attribute + "=" + value + ")").then(function (matches) {
+                    if (!matches) {
+                        throw "";
+                    }
+                    // On renvoit la valeur si elle est bien unique
+                    else if (matches.length = 0) {
+                        return value;
+                    }
+                    // Sinon, on tente de nouveau notre chance avec la valeur suivante
+                    else {
+                        return Tools.ensureUnique(changeValue(value, n + 1), attribute, domain, changeValue, n + 1);
+                    }
+                });
+            }
+            catch (err) {
+                throw "Erreur lors de la recherche d'une valeur pour assurer son unicité.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Cette fonction génère un uid standard, puis le fait évoluer jusqu'à ce qu'il soit unique.
+     * @desc Limité à un appel à {@link Tools.ensureUnique} 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
+     * @async
+     */
+    static generateUid(givenName, lastName, promotion) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // normalize et lowerCase standardisent le format
+                return Tools.ensureUnique((givenName + '.' + lastName).toLowerCase().normalize('UFD'), config_1.ldapConfig.key_id, "user", (id, n) => {
+                    if (n = 1) {
+                        id += '.' + promotion;
+                    } // Si prénom.nom existe déjà, on rajoute la promo
+                    else if (n = 2) {
+                        id += '.' + (n - 1).toString();
+                    } // Puis si prénom.nom.promo existe déjà on passe à nom.prenom.promo .1
+                    else if (n > 2) {
+                        id += n;
+                    } // Ensuite on continue .123, .1234, etc...
+                    return id;
+                });
+            }
+            catch (err) {
+                throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid).";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Cette fonction génère un id lisible, puis le fait évoluer jusqu'à ce qu'il soit unique.
+     * @desc Limité à un appel à {@link Tools.ensureUnique} 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
+     * @async
+     */
+    static generateReadableId(name) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                // normalize et lowerCase standardisent le format
+                return Tools.ensureUnique(name.toLowerCase().normalize('UFD'), config_1.ldapConfig.key_id, "group", (id, n) => {
+                    if (n = 1) {
+                        id += '.' + n.toString();
+                    } // Si nom existe déjà, on essaie nom.1
+                    else if (n > 1) {
+                        id += n.toString();
+                    } // Ensuite on continue .12, .123, etc...
+                    return id;
+                });
+            }
+            catch (err) {
+                throw "Erreur lors de l'assurance de l'unicité d'un human readable unique identifier (hruid).";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @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 {string} attribut - Intitulé exact de l'id concerné
+     * @param {"gr"|"us"} domain - Domaine dans lequel l'attribut doit être unique
+     * @return {Promise(string)} Valeur unique dans le domaine spécifié de l'attribut spécifié
+     * @static
+     * @async
+     */
+    static generateId(attribut, domain) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return Tools.ensureUnique("0", attribut, domain, (id, n) => { return Math.floor((Math.random() * 100000) + 1).toString(); });
+            }
+            catch (err) {
+                throw "Erreur lors de l'assurance de l'unicité d'un unique identifier numérique.";
+            }
+        });
+    }
+    /**
+     * @memberof LDAP
+     * @summary Fonction qui retrouve les utilisateurs ou groupes respectivement correspondant à un groupe ou un utilisateur de la même catégorie.
+     * @desc Cette fonction utilise {@link LDAP.search} et va directement à la feuille de l'utilisateur ou du groupe interrogé.
+     * Pour autant, elle est moins naïve qu'elle en a l'air. Elle ne gère ni la descente des admins ni la remontée des membres et renvoit une réponse naïve.
+     * @param {string} id - Identifiant du groupe ou de l'individu à interroger (supposé valide)
+     * @param {"user"|"group"} domain - Arbre à interroger
+     * @param {"admins"|"speakers"|"members"|"followers"} category - Catégorie considérée
+     * @return {Promise(string[])} Liste des id de groupes ou d'utilisateurs de la bonne catégorie associé à l'id
+     * @static
+     * @async
+     */
+    static get(id, domain, category) {
+        return __awaiter(this, void 0, void 0, function* () {
+            try {
+                return yield basics_1.Basics.searchSingle(domain, config_1.ldapConfig[domain][category], id);
+                // Ce qui suit est une récursion qui sera déplacée dans la gestion des autorisations 
+                if (!(category in ["admins", "members"]) || domain == "user") {
+                    return yield basics_1.Basics.searchSingle(domain, config_1.ldapConfig[domain][category], id);
+                }
+                else {
+                    // Clean depth-first search for inherited members and admins
+                    let stack = [];
+                    let res = [];
+                    let visited = {};
+                    stack.push(id);
+                    while (stack.length > 0) {
+                        let cur_id = stack.pop();
+                        if (visited[cur_id] == undefined) {
+                            visited[cur_id] = true;
+                            res.concat(yield basics_1.Basics.searchSingle("group", config_1.ldapConfig.group[category], cur_id));
+                            // In the end, the precise category only changes the iteration direction
+                            if (category == "members") {
+                                stack.concat(yield basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.childs, cur_id));
+                            }
+                            else {
+                                stack.concat(yield basics_1.Basics.searchSingle("group", config_1.ldapConfig.group.parents, cur_id));
+                            }
+                        }
+                    }
+                }
+            }
+            catch (err) {
+                throw "Erreur lors d'une recherche générique d'un membre d'une certaine catégorie d'un groupe.";
+            }
+        });
+    }
+}
+exports.Tools = Tools;
+//# sourceMappingURL=tools.js.map
\ No newline at end of file
diff --git a/tsbuild/src/ldap/internal/tools.js.map b/tsbuild/src/ldap/internal/tools.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..4f4cbfe3571539dea237c64f8f88f472bf5c53d7
--- /dev/null
+++ b/tsbuild/src/ldap/internal/tools.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../../src/ldap/internal/tools.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 89c4276a651bd7d5cd34e7ba347354de31b5a7f4..3eb90c043413c1eaf60ef6aef163b11551fa2e46 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,5 +1,5 @@
 {
-    "comment": "Fichier servant à la configuration des fichiers typescript, ou javascript typé",
+    "comment": "Fichier servant à la configuration des fichiers typescript, ou javascript typé (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)",
 	"compilerOptions": {
         "module": "commonjs",
         "esModuleInterop": true,
@@ -14,10 +14,5 @@
     "include": [
         "src/**/*",
         "db/**/*"
-    ],
-    "exclude": [
-        "node_modules",
-        "tsbuild",
-        "build"
-    ],
+    ]
 }
\ No newline at end of file