abilitiesUtils.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import {$accessProfile} from "@/services/profile/accessProfile"
  2. import {$organizationProfile} from "@/services/profile/organizationProfile"
  3. import {$roleUtils} from "~/services/rights/roleUtils";
  4. import {AbilitiesType, AnyJson, AnyStore} from "~/types/interfaces";
  5. import {Ability} from "@casl/ability";
  6. import * as _ from "lodash";
  7. import Serializer from "~/services/serializer/serializer";
  8. import {DENORMALIZER_TYPE} from "~/types/enums";
  9. /**
  10. * @category Services/droits
  11. * @class AbilitiesUtils
  12. * Classe permettant de mener des opérations sur les abilités
  13. */
  14. class AbilitiesUtils {
  15. private $store: AnyStore = {} as AnyStore
  16. private $ability: Ability = {} as Ability
  17. private factory: AnyJson = {}
  18. /**
  19. * @constructor
  20. */
  21. constructor(store: AnyStore, ability: Ability) {
  22. this.$store = store
  23. this.$ability = ability
  24. }
  25. /**
  26. * Initialise les services factories
  27. */
  28. initFactory() {
  29. this.factory = {
  30. access: $accessProfile(this.$store, this.$ability),
  31. organization: $organizationProfile(this.$store)
  32. }
  33. }
  34. /**
  35. * Set les abilities de l'utilisateur à chaque fois qu'on update son profile
  36. */
  37. setAbilities(){
  38. //Nécessaire pour que l'update des abilité soit correct après la phase SSR
  39. this.$ability.update(this.$store.state.profile.access.abilities);
  40. /**
  41. * Au moment où l'on effectue un SetProfile via le store Organization, il faut aller récupérer
  42. * les différentes abilitées que l'utilisateur peut effectuer. (Tout cela se passe en SSR)
  43. */
  44. const unsubscribe = this.$store.subscribeAction({
  45. after: (action, state) => {
  46. switch (action.type) {
  47. case 'profile/organization/setProfile':
  48. //On récupère les abilités
  49. const abilities = this.getAbilities();
  50. //On les store puis on update le service ability pour le mettre à jour.
  51. this.$store.commit('profile/access/setAbilities', abilities)
  52. this.$ability.update(abilities);
  53. //Unsubscribe pour éviter les memory leaks
  54. unsubscribe()
  55. break;
  56. }
  57. }
  58. })
  59. }
  60. /**
  61. * Récupération de l'ensemble des abilities quelles soient par Roles ou par Config.
  62. * @return {Array<AbilitiesType>}
  63. */
  64. getAbilities():Array<AbilitiesType> {
  65. const abilitiesByRoles = this.getAbilitiesByRoles(this.$store.state.profile.access.roles)
  66. this.$ability.update(abilitiesByRoles);
  67. this.initFactory();
  68. return abilitiesByRoles.concat(this.getAbilitiesByConfig('./config/abilities/config.yaml'))
  69. }
  70. /**
  71. * Adaptation et transformations des roles en abilities
  72. * @param {Array<string>} roles
  73. * @return {Array<AbilitiesType>}
  74. */
  75. getAbilitiesByRoles(roles: Array<string>): Array<AbilitiesType> {
  76. roles = $roleUtils.transformUnderscoreToHyphenBeforeCompleteMigration(roles);
  77. return $roleUtils.transformRoleToAbilities(roles);
  78. }
  79. /**
  80. * - Parcours la config d'abilities en Yaml
  81. * - filtres la config pour ne garder que les abilities autorisées
  82. * - transform la config restante en Object Abilities
  83. * @param {string} configPath
  84. * @return {Array<AbilitiesType>}
  85. */
  86. getAbilitiesByConfig(configPath:string): Array<AbilitiesType> {
  87. let abilitiesByConfig: Array<AbilitiesType> = []
  88. try {
  89. const serializer = new Serializer()
  90. const doc = serializer.denormalize({path: configPath}, DENORMALIZER_TYPE.YAML);
  91. const abilitiesAvailable = doc['abilities']
  92. const abilitiesFiltered = this.abilitiesAvailableFilter(abilitiesAvailable)
  93. abilitiesByConfig = this.transformAbilitiesConfigToAbility(abilitiesFiltered)
  94. } catch (e) {
  95. console.debug(e)
  96. }
  97. return abilitiesByConfig;
  98. }
  99. /**
  100. * Filtre toutes les abilities possible suivant si l'utilisateur est autorisé ou non à les posséder
  101. * @param {AnyJson} abilitiesAvailable
  102. * @return {AnyJson}
  103. */
  104. abilitiesAvailableFilter(abilitiesAvailable:AnyJson):AnyJson{
  105. return _.pickBy(abilitiesAvailable, (ability:any) =>{
  106. const services = ability['services']
  107. return this.canHaveTheAbility(services)
  108. })
  109. }
  110. /**
  111. * Transform une config d'abilities en un tableau d'Abilities
  112. * @param {AnyJson} abilitiesAvailable
  113. * @return {Array<AbilitiesType>}
  114. */
  115. transformAbilitiesConfigToAbility(abilitiesAvailable:AnyJson):Array<AbilitiesType>{
  116. let abilitiesByConfig: Array<AbilitiesType> = []
  117. _.each(abilitiesAvailable, (ability, subject) => {
  118. let myAbility: AbilitiesType = {
  119. action: ability['action'],
  120. subject: subject
  121. }
  122. abilitiesByConfig.push(myAbility)
  123. })
  124. return abilitiesByConfig;
  125. }
  126. /**
  127. * Parcours les fonctions par services et établit si oui ou non l'abilité est autorisée
  128. * @param {AnyJson} functionByservices
  129. * @return {boolean}
  130. */
  131. canHaveTheAbility(functionByservices: AnyJson) {
  132. let hasAbility = true;
  133. _.each(functionByservices, (functions, service) => {
  134. if (hasAbility) {
  135. const nbFunctions = functions.length
  136. let cmpt = 0
  137. while (hasAbility && nbFunctions > cmpt) {
  138. const f = functions[cmpt]['function'];
  139. const parameters = functions[cmpt]['parameters'] ?? null;
  140. const result = functions[cmpt]['result'] ?? null;
  141. hasAbility = result !== null ? this.factory[service].handler()[f](parameters) == result : this.factory[service].handler()[f](parameters)
  142. cmpt++
  143. }
  144. }
  145. })
  146. return hasAbility;
  147. }
  148. }
  149. export const $abilitiesUtils = (store: AnyStore, ability:Ability) => new AbilitiesUtils(store, ability);