abilityUtils.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import RoleUtils from '~/services/rights/roleUtils'
  2. import {AbilitiesType} from '~/types/interfaces'
  3. import YamlDenormalizer from "~/services/data/serializer/denormalizer/yamlDenormalizer";
  4. import {MongoAbility} from "@casl/ability/dist/types/Ability";
  5. import {AnyJson} from "~/types/data";
  6. import {useEach} from "#imports";
  7. import {ABILITIES} from "~/types/enum/enums";
  8. /**
  9. * Classe permettant de mener des opérations sur les habilités
  10. */
  11. class AbilityUtils {
  12. private readonly ability: MongoAbility = {} as MongoAbility
  13. private readonly accessProfile: any
  14. private readonly organizationProfile: any
  15. /**
  16. * @constructor
  17. */
  18. constructor(
  19. ability: MongoAbility,
  20. accessProfile: any,
  21. organizationProfile: any,
  22. ) {
  23. this.ability = ability
  24. this.accessProfile = accessProfile
  25. this.organizationProfile = organizationProfile
  26. }
  27. /**
  28. * Définit les abilities de l'utilisateur selon son profil
  29. */
  30. defineAbilities() {
  31. // Nécessaire pour que l'update des habilités soit correcte après la phase SSR
  32. this.ability.update(this.accessProfile.abilities)
  33. // Au moment où l'on effectue une action organizationProfileStore.setProfile, il faut aller récupérer
  34. // les différentes habilités que l'utilisateur peut effectuer. (Tout cela se passe en SSR)
  35. const unsubscribe = this.organizationProfile.$onAction(({
  36. name, // name of the action
  37. store, // store instance, same as `someStore`
  38. args, // array of parameters passed to the action
  39. after, // hook after the action returns or resolves
  40. onError, // hook if the action throws or rejects
  41. }: any) => {
  42. after((result: any)=>{
  43. if(name === 'setProfile'){
  44. //On récupère les habilités
  45. const abilities: Array<AbilitiesType> = this.buildAbilities();
  46. //On les store puis on update le service ability pour le mettre à jour.
  47. this.accessProfile.abilities = abilities
  48. this.ability.update(abilities)
  49. // Unsubscribe pour éviter les memory leaks
  50. unsubscribe()
  51. }
  52. })
  53. })
  54. }
  55. /**
  56. * Récupération de l'ensemble des habilités de l'utilisateur, qu'elles soient par Roles ou par Config
  57. *
  58. * @return {Array<AbilitiesType>}
  59. */
  60. buildAbilities(): Array<AbilitiesType> {
  61. const abilitiesByRoles: Array<AbilitiesType> = this.buildAbilitiesFromRoles(this.accessProfile.roles)
  62. this.ability.update(abilitiesByRoles)
  63. const abilitiesByConfig = this.buildAbilitiesFromConfig('./config/abilities/config.yaml')
  64. return abilitiesByRoles.concat(abilitiesByConfig)
  65. }
  66. /**
  67. * Adaptation et transformations des roles symfony en abilities Casl
  68. *
  69. * @param {Array<string>} roles
  70. * @return {Array<AbilitiesType>}
  71. */
  72. buildAbilitiesFromRoles(roles: Array<string>): Array<AbilitiesType> {
  73. return RoleUtils.rolesToAbilities(roles)
  74. }
  75. /**
  76. * Charge les habilités depuis les fichiers de configuration
  77. *
  78. * @param {string} configPath
  79. * @return {Array<AbilitiesType>}
  80. */
  81. buildAbilitiesFromConfig(configPath: string): Array<AbilitiesType> {
  82. const doc = YamlDenormalizer.denormalize({path: configPath})
  83. const fromConfig = doc.abilities
  84. const abilities: Array<AbilitiesType> = []
  85. useEach(fromConfig, (ability: { action: ABILITIES, services: object }, subject: string) => {
  86. const { action, services } = ability
  87. if (this.hasConfigAbility(services)) {
  88. abilities.push({ action, subject })
  89. }
  90. })
  91. return abilities
  92. }
  93. /**
  94. * Parcourt les services définis dans la configuration, et établit si oui ou non l'habilité est autorisée
  95. *
  96. * @return {boolean}
  97. * @param services
  98. */
  99. hasConfigAbility(services: AnyJson) {
  100. const handlerMap: any = {
  101. hasRole: (parameters: any) => this.hasRoles(parameters),
  102. hasAbility: (parameters: any) => this.hasAbilities(parameters),
  103. hasProfile: (parameters: any) => this.hasProfileAmong(parameters),
  104. isAdminAccount: (parameters: any) => this.accessProfile.isAdminAccount,
  105. hasModule: (parameters: any) => this.hasModule(parameters),
  106. isSchool: (parameters: any) => this.organizationProfile.isSchool,
  107. isArtist: (parameters: any) => this.organizationProfile.isArtist,
  108. isManagerProduct: (parameters: any) => this.organizationProfile.isManagerProduct,
  109. isOrganizationWithChildren: (parameters: any) => this.organizationProfile.hasChildren,
  110. isAssociation: (parameters: any) => this.organizationProfile.isAssociation,
  111. isShowAdherentList: (parameters: any) => this.organizationProfile.isShowAdherentList,
  112. isCmf: (parameters: any) => this.organizationProfile.isCmf,
  113. getWebsite: (parameters: any) => this.organizationProfile.getWebsite,
  114. }
  115. useEach(services, (handlers: Array<{ function: string, parameters?: Array<any>, result?: any }>, service: string) => {
  116. useEach(handlers, (handler: { function: string, parameters?: Array<any>, result?: any }) => {
  117. const expectedResult: boolean = handler.result ?? true;
  118. const parametersArray = handler.parameters ?? []
  119. useEach(parametersArray, (parameters: any) => {
  120. const actualResult = handlerMap[handler.function](parameters ?? null)
  121. if (actualResult !== expectedResult) {
  122. return false
  123. }
  124. })
  125. })
  126. })
  127. return true
  128. }
  129. /**
  130. * Est-ce que l'utilisateur possède la ou les habilités
  131. *
  132. * @param {Array<AbilitiesType>} abilities Habilités à tester
  133. * @return {boolean}
  134. */
  135. hasAbilities(abilities: Array<AbilitiesType>|null): boolean{
  136. useEach(abilities ?? [], (ability) => {
  137. if (!this.ability.can(ability.action, ability.subject)) {
  138. return false
  139. }
  140. })
  141. return true
  142. }
  143. /**
  144. * Teste le profil d'un utilisateur
  145. *
  146. * @param {string} profile : profile à tester
  147. * @return {boolean}
  148. */
  149. private testProfile(profile: string): boolean {
  150. const factory: {[key: string]: boolean|null} = {
  151. 'admin': this.accessProfile.isAdmin,
  152. 'administratifManager': this.accessProfile.isAdministratifManager,
  153. 'pedagogicManager': this.accessProfile.isPedagogicManager,
  154. 'financialManager': this.accessProfile.isFinancialManager,
  155. 'caMember': this.accessProfile.isCaMember,
  156. 'student': this.accessProfile.isStudent,
  157. 'teacher': this.accessProfile.isTeacher,
  158. 'member': this.accessProfile.isMember,
  159. 'other': this.accessProfile.isOther,
  160. 'guardian': this.accessProfile.isGuardian,
  161. 'payor': this.accessProfile.isPayer,
  162. }
  163. return factory[profile] ?? false
  164. }
  165. /**
  166. * Retourne vrai si l'utilisateur connecté possède l'un des profils passés en paramètre
  167. *
  168. * @param {Array<string>} profiles Profils à tester
  169. * @return {boolean}
  170. */
  171. hasProfileAmong (profiles: Array<string>|null): boolean {
  172. if (null === profiles)
  173. return true;
  174. useEach(profiles, (profile) => {
  175. if (this.testProfile(profile)) {
  176. return true
  177. }
  178. })
  179. return false
  180. }
  181. /**
  182. * Est-ce que l'utilisateur possède le rôle donné ?
  183. *
  184. * @return {boolean}
  185. * @param role
  186. */
  187. hasRole(role: string|null): boolean {
  188. return role === null || this.accessProfile.roles.includes(role)
  189. }
  190. /**
  191. * Est-ce que l'utilisateur possède tous les rôles donnés ?
  192. *
  193. * @return {boolean}
  194. * @param roles
  195. */
  196. hasRoles(roles: Array<string>): boolean {
  197. useEach(roles, (r: string) => {
  198. if (!this.accessProfile.roles.includes(r)) {
  199. return false
  200. }
  201. })
  202. return true
  203. }
  204. /**
  205. * Est-ce que l'organisation possède le module donné
  206. *
  207. * @return {boolean}
  208. * @param module
  209. */
  210. hasModule(module: string): boolean {
  211. return this.organizationProfile.modules.includes(module)
  212. }
  213. }
  214. export default AbilityUtils