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