import { AbilitiesType } from '~/types/interfaces' import {AnyJson} from "~/types/data" import * as _ from 'lodash-es' // 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 actions = ['VIEW', 'REFERENCE', 'CORE'] const actionMap: AnyJson = { '': 'manage', 'VIEW': 'read', 'REFERENCE': null, 'CORE': null, } interface Role { subject: string action: 'VIEW' | 'CORE' | 'REFERENCE' | '' } /** * 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 correspondant à 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) }) } /** * Parse une chaine de caractère décrivant un rôle applicatif * * @param role */ static parseRole(role: string): Role { const parts = role.split('_') if (parts[0] !== 'ROLE') { throw new Error('can not parse role') } parts.shift() let action: 'VIEW' | 'CORE' | 'REFERENCE' | '' = '' if (actions.includes(parts.at(-1) ?? '')) { // @ts-ignore action = parts.pop() ?? '' } const subject = parts.join('-') return { subject, action } } static roleToString(role: Role) { // TODO: est-ce qu'il faut retransformer les - en _ ? (si oui, attention à maj les tests) return ['ROLE', role.subject, role.action].filter((s: string) => s !== null && s.length > 0).join('_') } /** * Construit une habilité à partir du rôle en paramètre. * Retourne null si le role ne donne droit à aucune habilité * @param role */ static roleToAbility(role: Role): AbilitiesType | null { const mappedAction = actionMap[role.action] if (mappedAction === null) { return null } return { action: mappedAction, subject: role.subject.toLowerCase() } } /** * 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 = [] _.each(roles, (role: string) => { const parsed: Role | null= RoleUtils.parseRole(role) const ability = RoleUtils.roleToAbility(parsed) // @ts-ignore if (ability !== null && ability.subject && typeof ability.action !== 'undefined') { abilities.push(ability) } }) return abilities } } export default RoleUtils