import { AbilitiesType } from '~/types/interfaces' import {AnyJson} from "~/types/data" import _ from "lodash" // TODO: peut-être passer ces constantes dans la config? const rolesByFunction: Array = [ 'ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_ADMIN_CORE', 'ROLE_ADMINISTRATIF_MANAGER', 'ROLE_ADMINISTRATIF_MANAGER_CORE', 'ROLE_PEDAGOGICS_MANAGER', 'ROLE_PEDAGOGICS_MANAGER_CORE', 'ROLE_FINANCIAL_MANAGER', 'ROLE_FINANCIAL_MANAGER_CORE', 'ROLE_CA', 'ROLE_CA_CORE', 'ROLE_STUDENT', 'ROLE_STUDENT_CORE', 'ROLE_TEACHER', 'ROLE_TEACHER_CORE', 'ROLE_MEMBER', 'ROLE_MEMBER_CORE', 'ROLE_OTHER', 'ROLE_OTHER_CORE' ] const rolesToChange: Array = [ 'ROLE_GENERAL_CONFIG', 'ROLE_GENERAL_CONFIG_VIEW', 'ROLE_TAGG_ADVANCED', 'ROLE_TAGG_ADVANCED_VIEW', 'ROLE_PEDAGOGICS_ADMINISTRATION', 'ROLE_PEDAGOGICS_ADMINISTRATION_VIEW', 'ROLE_PEDAGOGICS_SEIZURE', 'ROLE_PEDAGOGICS_SEIZURE_VIEW', 'ROLE_BILLINGS_ADMINISTRATION', 'ROLE_BILLINGS_ADMINISTRATION_VIEW', 'ROLE_BILLINGS_SEIZURE', 'ROLE_BILLINGS_SEIZURE_VIEW', 'ROLE_ONLINEREGISTRATION_ADMINISTRATION', 'ROLE_ONLINEREGISTRATION_ADMINISTRATION_VIEW' ] const actionMap: AnyJson = { '': 'manage', _VIEW: 'read' } /** * Classe permettant de mener des opérations sur les rôles */ class RoleUtils { /** * Teste si une personne possède un profil suivant ses rôles * * @param {string} profileName * @param {Array} roles * @return {boolean} */ static isA (profileName: string, roles: Array): boolean { profileName = profileName.toUpperCase() if (!profileName.match(/^[A-Z_]+$/)) { throw new Error('invalid role name') } // TODO: actuellement, passer un profil ne corresondant à aucun rôle ne lèvera aucune erreur, et se contentera de // retourner false; ce serait pas mal de lever une erreur, ce ne serait pas normal de demander un rôle inexistant return roles.includes('ROLE_' + profileName + '_CORE') } /** * Filtre les rôles afin d'en exclure les "Roles fonctions" * * @param {Array} roles * @return {Array} */ static filterFunctionRoles (roles: Array): Array { return roles.filter((role) => { return !rolesByFunction.includes(role) }) } /** * Fix en attendant la migration complète, quelques rôles disposent d'underscore en trop, on corrige cela... * * TODO: remove after complete migration * * @param {Array} roles * @return {Array} */ static transformUnderscoreToHyphen (roles: Array): Array { // TODO: clarifier le fonctionnement de cette méthode et de la regex, qu'est-ce qui sépare le groupe 2 et 3 au final? const regex = /(ROLE_)([A-Z]*_[A-Z]*)([A-Z_]*)*/i let match roles = roles.map((role) => { if (rolesToChange.includes(role)) { if ((match = regex.exec(role)) !== null) { const role = match[1] const subject = match[2].replace('_', '-') const action = match[3] return role + subject + (action || '') } } return role }) return roles } /** * On transforme les ROLES Symfony en Abilities * * Ex: * * "ROLE_ORGANIZATION" => { subject: 'organization', action: 'manage'} * "ROLE_PLACE_VIEW" => { subject: 'place', action: 'read'} * * @param {Array} roles * @return {Array} */ static rolesToAbilities (roles: Array): [] | Array { const abilities:Array = [] roles = RoleUtils.transformUnderscoreToHyphen(roles) // TODO: on pourrait peut-être faciliter la lecture en réécrivant la regex en `ROLE_([A-Z-]*)(_[A-Z]+)?`, ou // même en faisant un simple split sur le '_' const regex = /(ROLE_)([A-Z-]*)([_A-Z]*)/i let match _.each(roles, (role) => { if ((match = regex.exec(role)) !== null) { const subject = match[2] const actionName = match[3] ?? '' const action = actionMap[actionName] if (subject && typeof action !== 'undefined') { abilities.push({ action: action, subject: subject.toLowerCase() }) } } }) return abilities } } export default RoleUtils