abilityUtils.ts 9.5 KB

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