import {accessProfile} from "@/services/profile/accessProfile" import {organizationProfile} from "@/services/profile/organizationProfile" import {$roleUtils} from "~/services/rights/roleUtils"; import {AbilitiesType, AccessStore, AnyJson, AnyStore} from "~/types/types"; import {Ability} from "@casl/ability"; import YamlParser from "~/services/utils/yamlParser"; import * as _ from "lodash"; /** * @category Services/droits * @class AbilitiesUtils * Classe permettant de mener des opérations sur les abilités */ class AbilitiesUtils { private $store: AnyStore = {} as AnyStore private $ability: Ability = {} as Ability private factory: AnyJson = {} /** * @constructor */ constructor(store: AnyStore, ability: Ability) { this.$store = store this.$ability = ability } /** * Initialise les services factories */ initFactory() { this.factory = { access: accessProfile(this.$store, this.$ability), organization: organizationProfile(this.$store) } } /** * Récupération de l'ensemble des abilities quelles soient par Roles ou par Config. * @returns {Array} */ getAbilities():Array { const abilitiesByRoles = this.getAbilitiesByRoles(this.$store.state.profile.access.roles) this.$ability.update(abilitiesByRoles); this.initFactory(); return abilitiesByRoles.concat(this.getAbilitiesByConfig('./config/abilities/config.yaml')) } /** * Adaptation et transformations des roles en abilities * @param {Array} roles * @returns {Array} */ getAbilitiesByRoles(roles: Array): Array { roles = $roleUtils.transformUnderscoreToHyphenBeforeCompleteMigration(roles); return $roleUtils.transformRoleToAbilities(roles); } /** * - Parcours la config d'abilities en Yaml * - filtres la config pour ne garder que les abilities autorisées * - transform la config restante en Object Abilities * @param {string} configPath * @returns {Array} */ getAbilitiesByConfig(configPath:string): Array { let abilitiesByConfig: Array = [] try { const doc = YamlParser.parse(configPath); const abilitiesAvailable = doc['abilities'] const abilitiesFiltered = this.abilitiesAvailableFilter(abilitiesAvailable) abilitiesByConfig = this.transformAbilitiesConfigToAbility(abilitiesFiltered) } catch (e) { console.debug(e) } return abilitiesByConfig; } /** * Filtre toutes les abilities possible suivant si l'utilisateur est autorisé ou non à les posséder * @param {AnyJson} abilitiesAvailable * @returns {AnyJson} */ abilitiesAvailableFilter(abilitiesAvailable:AnyJson):AnyJson{ return _.pickBy(abilitiesAvailable, (ability:any) =>{ const services = ability['services'] return this.canHaveTheAbility(services) }) } /** * Transform une config d'abilities en un tableau d'Abilities * @param {AnyJson} abilitiesAvailable * @returns {Array} */ transformAbilitiesConfigToAbility(abilitiesAvailable:AnyJson):Array{ let abilitiesByConfig: Array = [] _.each(abilitiesAvailable, (ability, subject) => { let myAbility: AbilitiesType = { action: ability['action'], subject: subject } abilitiesByConfig.push(myAbility) }) return abilitiesByConfig; } /** * Parcours les fonctions par services et établit si oui ou non l'abilité est autorisée * @param {AnyJson} functionByservices * @returns {boolean} */ canHaveTheAbility(functionByservices: AnyJson) { let hasAbility = true; _.each(functionByservices, (functions, service) => { if (hasAbility) { const nbFunctions = functions.length let cmpt = 0 while (hasAbility && nbFunctions > cmpt) { const f = functions[cmpt]['function']; const parameters = functions[cmpt]['parameters'] ?? null; const result = functions[cmpt]['result'] ?? null; hasAbility = result !== null ? this.factory[service].handler()[f](parameters) == result : this.factory[service].handler()[f](parameters) cmpt++ } } }) return hasAbility; } } export const $abilitiesUtils = (store: AnyStore, ability:Ability) => new AbilitiesUtils(store, ability);