abilitiesUtils.ts 5.6 KB

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