Forked from an inaccessible project.
-
Olivér FACKLAM authoredOlivér FACKLAM authored
tools.ts 8.85 KiB
/**
* Namespace qui regroupe toutes les classes et toutes les fonctions qui permettent l'implémentation des resolvers du schéma GraphQL
* @namespace GraphQL
*/
/**
* @file Fonctions génériques de recherche dans la BDD et le LDAP réutilisables dans l'authorization et/ou dans les resolvers
* @author ofacklam
* @memberof GraphQL
*/
import { userData } from '../../ldap/export/user'
import { groupData, Group as GT } from '../../ldap/export/group';
import knex from '../../../db/knex_router';
export class GroupSet extends Set<string> {
addList(l: string[]) {
for(let elt of l) this.add(elt);
}
}
export interface GroupCollection {
simpleGroups: GroupSet,
metaGroups: GroupSet
}
export 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: string) {
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: GroupSet, B: GroupSet): GroupSet {
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 async memberOfSimple(data: userData): Promise<GroupSet> {
//Do a DFS from data.members to find all parents
//return Tools.DFS(data.members, 'parent');
//No need to do DFS
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 async speakerOfSimple(data: userData): Promise<GroupSet> {
return new GroupSet(data.speakers);
}
/**
* @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 async adminOfSimple(data: userData): Promise<GroupSet> {
//Do a DFS from data.admins to find all children
//return Tools.DFS(data.admins, 'child');
//No need to do DFS
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 async metaGroupsOfGroups(groups: GroupSet): Promise<GroupSet> {
let metas = await knex.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 async memberOf(data: userData): Promise<GroupCollection> {
let simple = await Tools.memberOfSimple(data);
return { simpleGroups: simple, metaGroups: await 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 async speakerOf(data: userData): Promise<GroupCollection> {
let simple = await Tools.speakerOfSimple(data);
return { simpleGroups: simple, metaGroups: await Tools.metaGroupsOfGroups(simple) };
}
/**
* @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 async adminOf(data: userData): Promise<GroupCollection> {
let simple = await Tools.adminOfSimple(data);
return { simpleGroups: simple, metaGroups: await Tools.metaGroupsOfGroups(simple) };
}
/**
* @memberof GraphQL
* @summary Fonction qui fait un parcours en profondeur du graphe a partir de 'roots' et renvoie la liste de tous les noeuds dans la direction donnée.
* @arg {string[]} roots - Identifiants des groupes racine, supposés valides.
* @arg {'parent'|'child'} direction - Direction de la recherche. 'parent' cherche tous les noeuds ascendants. 'child' cherche tous les noeuds descendants.
* @return {Promise(GroupSet)} Renvoie un ensemble contenant le nom des groupes dans cette direction.
* @static
* @async
*/
static async DFS(roots : string[], direction : 'parent'|'child'): Promise<GroupSet> {
let stack = roots.slice();
let visited = {};
let res = new GroupSet();
while(stack.length > 0) {
let gid = stack.pop();
if(visited[gid] !== true) {
visited[gid] = true;
res.add(gid);
//console.log(gid);
if(direction === 'child') {
let gd = new groupData();
gd.parents = [gid]; //on cherche les enfants, ie tous les groupes qui ont `gid` comme parent
stack.push(...await GT.search(gd));
}
else {
let data = await GT.peek(gid);
stack.push(...data.parents)
}
}
}
return res;
}
/**
* @memberof GraphQL
* @summary Fonction qui renvoie la liste des enfants des noeuds de `roots`.
* @arg {GroupSet} roots - Identifiants des groupes racine, supposés valides.
* @return {Promise(string[])} Renvoie une liste contenant le nom des groupes enfants (!! doublons !!).
* @static
* @async
*/
static async oneDownSearch(roots: GroupSet): Promise<string[]> {
let res = [];
for(let r of roots) {
let gd = new groupData();
gd.parents = [r]; //on cherche les enfants, ie tous les groupes qui ont `r` comme parent
res.push(...await GT.search(gd));
}
return res;
}
/**
* @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 {GroupCollection} groups - Groupes dont le user est membre hérité.
* @return {Promise(GroupCollection)} Renvoie une GroupCollection contenant le nom des groupes.
* @static
* @async
*/
static async viewerOf(groups: GroupCollection): Promise<GroupCollection> {
let simple = groups.simpleGroups;
//Ajouter les groupes enfants
simple.addList(await Tools.oneDownSearch(simple));
//Ajouter les groupes simples qui sont dans ses métagroupes
let s = await knex.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: await Tools.metaGroupsOfGroups(simple) };
}
}