diff --git a/ldap_config.json b/ldap_config.json index d981c3f9b8286e97291ea413800ee61cef37599a..7eeba1cc8c89c1e222203795f7e134547e28b4fa 100644 --- a/ldap_config.json +++ b/ldap_config.json @@ -53,7 +53,6 @@ "password": "userPassword", "logo": "jpegPhoto", "classes": "objectClass", - "childs": "child", "parents": "parent" } } \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 3ad874843269daddf8d4abef4a5768067fc2eaac..1702ae601e66b59276f9162e75cf9c11a36f722b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -209,7 +209,7 @@ const context = async ({ req }): Promise<Context> => { } } console.log(`Constructing context with uid = ${uid}`); - /*return { + let c = { request: req, user: { uid: uid }, models: { @@ -219,21 +219,9 @@ const context = async ({ req }): Promise<Context> => { message: new MessageModel(uid), request: new RequestModel(uid) } - };*/ - let blah = { - request: req, - user: { uid: uid }, - //models: null - models: { - auth: await AuthorizationModel.create(uid), - user: null,//new UserModel(uid), - group: null,//new GroupModel(uid), - message: null,//new MessageModel(uid), - request: null,//new RequestModel(uid) - } }; console.log("finished constructing context"); - return blah; + return c; }; const server = new ApolloServer({ diff --git a/src/graphql/models/authorization.ts b/src/graphql/models/authorization.ts index a4dc65cb588421cdd7392abe635f4488bc91a033..97a18d7fc2e0cca908d445eac4191fc6a88301f4 100644 --- a/src/graphql/models/authorization.ts +++ b/src/graphql/models/authorization.ts @@ -8,14 +8,13 @@ import { Tools, GroupSet, GroupCollection } from "./tools"; import { User as UT } from '../../ldap/export/user' /* - * There are 7 levels of authorization + * There are 6 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 */ export class AuthorizationModel { @@ -55,7 +54,6 @@ export class AuthorizationModel { protected memberOf: GroupCollection; protected speakerOf: GroupCollection; protected adminOf: GroupCollection; - protected supervisorOf: GroupCollection; static PUBLICUSER = "public_user"; static ONPLATALUSER = "public_onplatal_user"; @@ -72,11 +70,11 @@ export class AuthorizationModel { console.log("UT.peek returned with data:"); //console.log(data); - this.viewerOf = await Tools.viewerOf(data); this.memberOf = await Tools.memberOf(data); - this.speakerOf = await Tools.viewerOf(data); + this.speakerOf = await Tools.speakerOf(data); this.adminOf = await Tools.adminOf(data); - this.supervisorOf = await Tools.supervisorOf(data); + this.viewerOf = await Tools.viewerOf(this.memberOf); + //console.log(this.viewerOf); } /** @@ -232,12 +230,7 @@ export class AuthorizationModel { //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 (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid)); } return false; } @@ -256,34 +249,4 @@ export class AuthorizationModel { 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: string): boolean { - //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(): GroupCollection { - //ensure uid is valid !!!!!!!! - if (this.isAuthenticated()) { - return this.supervisorOf; - } - return null; - } - } \ No newline at end of file diff --git a/src/graphql/models/tools.ts b/src/graphql/models/tools.ts index 1e01268fa3f84e6a17b798cf72b982b2a0d792af..1b24e6be7526a1897f597c6d05e6d32faf7d4ffa 100644 --- a/src/graphql/models/tools.ts +++ b/src/graphql/models/tools.ts @@ -10,6 +10,7 @@ */ 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> { @@ -70,8 +71,8 @@ export class Tools { * @async */ static async memberOfSimple(data: userData): Promise<GroupSet> { - throw "Not implemented"; - return new GroupSet(data.members); + //Do a DFS from data.members to find all parents + return Tools.DFS(data.members, 'parent'); } /** @@ -83,9 +84,7 @@ export class Tools { * @async */ static async speakerOfSimple(data: userData): Promise<GroupSet> { - let speaker = new GroupSet(data.speakers); - speaker.addList(data.admins); - return speaker; + return new GroupSet(data.speakers); } /** @@ -97,8 +96,8 @@ export class Tools { * @async */ static async adminOfSimple(data: userData): Promise<GroupSet> { - throw "Not implemented"; - return new GroupSet(data.admins); + //Do a DFS from data.admins to find all children + return Tools.DFS(data.admins, 'child'); } /** @@ -110,7 +109,7 @@ export class Tools { * @async */ static async metaGroupsOfGroups(groups: GroupSet): Promise<GroupSet> { - let metas = await knex.select('meta_group_gid').from('metagroup_memberships').whereIn('simple_group_gid', groups); + 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; })); @@ -139,8 +138,7 @@ export class Tools { */ static async speakerOf(data: userData): Promise<GroupCollection> { let speaker = await Tools.speakerOfSimple(data); - let admin = await Tools.adminOfSimple(data); - return { simpleGroups: speaker, metaGroups: await Tools.metaGroupsOfGroups(admin) }; + return { simpleGroups: speaker, metaGroups: await Tools.metaGroupsOfGroups(new GroupSet(data.admins)) }; } /** @@ -158,19 +156,36 @@ export class Tools { /** * @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. + * @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(gid: string): Promise<string[]> { - let res = [gid]; - let children = await knex.select('gid').from('groups').where('parent_gid', gid); - - for(let child of children) { - let sub_tree = await Tools.DFS(child.gid); - res = res.concat(sub_tree); + 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); + if(data.parents !== undefined) stack.push(...data.parents) + } + + } } return res; @@ -178,79 +193,47 @@ export class Tools { /** * @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. + * @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(gid: string): Promise<string[]> { - let res = [gid]; - let children = await knex.select('gid').from('groups').where('parent_gid', gid); + static async oneDownSearch(roots: GroupSet): Promise<string[]> { + let res = []; - for (let child of children) { - res.push(child.gid); + 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 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 async supervisorOf(data: userData): Promise<GroupCollection> { - let groups = await Tools.adminOf(data); - - let simple = new GroupSet(); - let meta = new GroupSet(); - - for(let g of groups.simpleGroups) { - simple.addList(await Tools.oneDownSearch(g)); - } - for(let g of groups.metaGroups) { - meta.addList(await 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. + * @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(data: userData): Promise<GroupCollection> { - let groups = await Tools.memberOf(data); + static async viewerOf(groups: GroupCollection): Promise<GroupCollection> { + let simple = groups.simpleGroups; - 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(await Tools.oneDownSearch(g)); - } - for(let g of groups.metaGroups) { - meta.addList(await Tools.oneDownSearch(g)); - } + //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); + 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: meta }; + return { simpleGroups: simple, metaGroups: await Tools.metaGroupsOfGroups(simple) }; } } \ No newline at end of file