oxutils 0.5.0__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. {oxutils-0.5.0 → oxutils-0.5.2}/PKG-INFO +1 -1
  2. {oxutils-0.5.0 → oxutils-0.5.2}/pyproject.toml +2 -1
  3. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/__init__.py +2 -2
  4. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/models.py +2 -1
  5. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/utils.py +5 -5
  6. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/authorization.py +13 -7
  7. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/controllers.py +18 -18
  8. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/management/commands/init_oxiliere_system.py +6 -1
  9. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/services.py +7 -3
  10. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/actions.py +3 -8
  11. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/caches.py +15 -16
  12. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/checks.py +16 -24
  13. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/exceptions.py +24 -14
  14. oxutils-0.5.2/src/oxutils/permissions/locale/fr/LC_MESSAGES/django.po +130 -0
  15. oxutils-0.5.2/src/oxutils/permissions/management/commands/load_permission_preset.py +91 -0
  16. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/models.py +1 -1
  17. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/queryset.py +2 -0
  18. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/services.py +298 -268
  19. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/utils.py +127 -110
  20. oxutils-0.5.0/src/oxutils/pagination/cursor.py +0 -367
  21. oxutils-0.5.0/src/oxutils/permissions/locale/fr/LC_MESSAGES/django.po +0 -78
  22. oxutils-0.5.0/src/oxutils/permissions/management/commands/load_permission_preset.py +0 -112
  23. oxutils-0.5.0/src/oxutils/users/migrations/__init__.py +0 -0
  24. {oxutils-0.5.0 → oxutils-0.5.2}/README.md +0 -0
  25. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/apps.py +0 -0
  26. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/__init__.py +0 -0
  27. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/apps.py +0 -0
  28. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/export.py +0 -0
  29. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/locale/fr/LC_MESSAGES/django.po +0 -0
  30. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/masks.py +0 -0
  31. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/migrations/0001_initial.py +0 -0
  32. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/migrations/__init__.py +0 -0
  33. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/models.py +0 -0
  34. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/settings.py +0 -0
  35. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/audit/utils.py +0 -0
  36. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/__init__.py +0 -0
  37. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/adapter.py +0 -0
  38. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/admin.py +0 -0
  39. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/app_settings.py +0 -0
  40. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/apps.py +0 -0
  41. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/constants.py +0 -0
  42. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/controllers.py +0 -0
  43. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/emails/__init__.py +0 -0
  44. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/emails/controllers.py +0 -0
  45. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/emails/schemas.py +0 -0
  46. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/emails/services.py +0 -0
  47. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/exceptions.py +0 -0
  48. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/__init__.py +0 -0
  49. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/backend.py +0 -0
  50. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/controllers.py +0 -0
  51. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/models.py +0 -0
  52. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/schemas.py +0 -0
  53. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/invitations/tokens.py +0 -0
  54. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/__init__.py +0 -0
  55. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/adapter.py +0 -0
  56. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/base/__init__.py +0 -0
  57. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/base/controllers.py +0 -0
  58. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/base/schemas.py +0 -0
  59. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/recovery_codes/__init__.py +0 -0
  60. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/recovery_codes/controllers.py +0 -0
  61. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/recovery_codes/flows.py +0 -0
  62. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/recovery_codes/schemas.py +0 -0
  63. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/recovery_codes/services.py +0 -0
  64. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/__ini__.py +0 -0
  65. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/controllers.py +0 -0
  66. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/flows.py +0 -0
  67. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/permissions.py +0 -0
  68. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/schemas.py +0 -0
  69. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/totp/services.py +0 -0
  70. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mfa/utils.py +0 -0
  71. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/migrations/0001_initial.py +0 -0
  72. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/migrations/__init__.py +0 -0
  73. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/mixins.py +0 -0
  74. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/models.py +0 -0
  75. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/password_reset/__init__.py +0 -0
  76. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/password_reset/controllers.py +0 -0
  77. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/password_reset/models.py +0 -0
  78. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/password_reset/permissions.py +0 -0
  79. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/password_reset/schemas.py +0 -0
  80. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/registration/__init__.py +0 -0
  81. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/registration/controllers.py +0 -0
  82. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/registration/schemas.py +0 -0
  83. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/schemas.py +0 -0
  84. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/sessions/__init__.py +0 -0
  85. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/sessions/controllers.py +0 -0
  86. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/sessions/schemas.py +0 -0
  87. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/signals.py +0 -0
  88. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/templatetags/__init__.py +0 -0
  89. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/templatetags/spa_urls.py +0 -0
  90. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/__init__.py +0 -0
  91. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/app_settings.py +0 -0
  92. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/models.py +0 -0
  93. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/schemas.py +0 -0
  94. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/tokens.py +0 -0
  95. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/tokens/utils.py +0 -0
  96. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/auth/utils.py +0 -0
  97. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/celery/__init__.py +0 -0
  98. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/celery/base.py +0 -0
  99. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/celery/settings.py +0 -0
  100. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/conf.py +0 -0
  101. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/constants.py +0 -0
  102. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/context/__init__.py +0 -0
  103. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/context/site_name_processor.py +0 -0
  104. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/__init__.py +0 -0
  105. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/admin.py +0 -0
  106. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/apps.py +0 -0
  107. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/caches.py +0 -0
  108. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/controllers.py +0 -0
  109. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/enums.py +0 -0
  110. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/management/__init__.py +0 -0
  111. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/management/commands/__init__.py +0 -0
  112. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/management/commands/sync_currency.py +0 -0
  113. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/migrations/0001_initial.py +0 -0
  114. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/migrations/__init__.py +0 -0
  115. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/schemas.py +0 -0
  116. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/signals.py +0 -0
  117. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/tests.py +0 -0
  118. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/currency/utils.py +0 -0
  119. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/enums/__init__.py +0 -0
  120. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/enums/audit.py +0 -0
  121. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/enums/invoices.py +0 -0
  122. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/exceptions.py +0 -0
  123. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/functions.py +0 -0
  124. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/__init__.py +0 -0
  125. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/auth.py +0 -0
  126. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/middleware.py +0 -0
  127. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/models.py +0 -0
  128. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/jwt/tokens.py +0 -0
  129. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/logger/__init__.py +0 -0
  130. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/logger/receivers.py +0 -0
  131. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/logger/settings.py +0 -0
  132. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/mixins/__init__.py +0 -0
  133. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/mixins/base.py +0 -0
  134. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/mixins/schemas.py +0 -0
  135. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/mixins/services.py +0 -0
  136. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/__init__.py +0 -0
  137. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/base.py +0 -0
  138. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/billing.py +0 -0
  139. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/change_tracker.py +0 -0
  140. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/fields.py +0 -0
  141. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/models/invoice.py +0 -0
  142. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/__init__.py +0 -0
  143. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/admin.py +0 -0
  144. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/apps.py +0 -0
  145. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/cacheops.py +0 -0
  146. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/caches.py +0 -0
  147. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/checks.py +0 -0
  148. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/constants.py +0 -0
  149. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/context.py +0 -0
  150. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/enums.py +0 -0
  151. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/exceptions.py +0 -0
  152. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/locale/fr/LC_MESSAGES/django.po +0 -0
  153. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/management/__init__.py +0 -0
  154. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/management/commands/__init__.py +0 -0
  155. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/management/commands/grant_tenant_owners.py +0 -0
  156. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/middleware.py +0 -0
  157. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/migrations/__init__.py +0 -0
  158. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/models.py +0 -0
  159. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/permissions.py +0 -0
  160. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/schemas.py +0 -0
  161. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/settings.py +0 -0
  162. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/signals.py +0 -0
  163. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/tests.py +0 -0
  164. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/oxiliere/utils.py +0 -0
  165. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/pdf/__init__.py +0 -0
  166. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/pdf/printer.py +0 -0
  167. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/pdf/utils.py +0 -0
  168. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/pdf/views.py +0 -0
  169. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/__init__.py +0 -0
  170. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/admin.py +0 -0
  171. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/apps.py +0 -0
  172. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/constants.py +0 -0
  173. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/controllers.py +0 -0
  174. {oxutils-0.5.0/src/oxutils/pagination → oxutils-0.5.2/src/oxutils/permissions/management}/__init__.py +0 -0
  175. {oxutils-0.5.0/src/oxutils/permissions/management → oxutils-0.5.2/src/oxutils/permissions/management/commands}/__init__.py +0 -0
  176. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0001_initial.py +0 -0
  177. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0002_alter_grant_role.py +0 -0
  178. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +0 -0
  179. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0004_group_app_group_permissions_app_9a9924_idx.py +0 -0
  180. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0005_role_app.py +0 -0
  181. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0006_alter_rolegrant_options_and_more.py +0 -0
  182. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0007_grant_locked_alter_grant_role_and_more.py +0 -0
  183. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0008_remove_grant_unique_user_scope_role_and_more.py +0 -0
  184. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0009_grant_is_active.py +0 -0
  185. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/migrations/0010_increase_action_max_length.py +0 -0
  186. {oxutils-0.5.0/src/oxutils/permissions/management/commands → oxutils-0.5.2/src/oxutils/permissions/migrations}/__init__.py +0 -0
  187. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/permissions.py +0 -0
  188. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/perms.py +0 -0
  189. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/presets.py +0 -0
  190. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/schemas.py +0 -0
  191. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/permissions/tests.py +0 -0
  192. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/py.typed +0 -0
  193. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/s3.py +0 -0
  194. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/settings.py +0 -0
  195. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/account/email/base_message.txt +0 -0
  196. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/email/password/reset_email_message.html +0 -0
  197. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/email/password/reset_email_message.txt +0 -0
  198. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/email/password/reset_email_subject.txt +0 -0
  199. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/email/signup/email_message.html +0 -0
  200. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/email/signup/email_subject.txt +0 -0
  201. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/templates/verified.html +0 -0
  202. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/types.py +0 -0
  203. {oxutils-0.5.0/src/oxutils/permissions/migrations → oxutils-0.5.2/src/oxutils/users}/__init__.py +0 -0
  204. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/admin.py +0 -0
  205. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/apps.py +0 -0
  206. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/locale/fr/LC_MESSAGES/django.po +0 -0
  207. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/migrations/0001_initial.py +0 -0
  208. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +0 -0
  209. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/migrations/0003_user_photo.py +0 -0
  210. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/migrations/0004_alter_user_options.py +0 -0
  211. {oxutils-0.5.0/src/oxutils/users → oxutils-0.5.2/src/oxutils/users/migrations}/__init__.py +0 -0
  212. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/models.py +0 -0
  213. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/tests.py +0 -0
  214. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/users/utils.py +0 -0
  215. {oxutils-0.5.0 → oxutils-0.5.2}/src/oxutils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxutils
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: Production-ready utilities for Django applications in the Oxiliere ecosystem
5
5
  Keywords: django,utilities,jwt,audit,logging,celery,structlog
6
6
  Author: Edimedia Mutoke
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "oxutils"
3
- version = "0.5.0"
3
+ version = "0.5.2"
4
4
  description = "Production-ready utilities for Django applications in the Oxiliere ecosystem"
5
5
  readme = "README.md"
6
6
  license = "LGPL-3.0-only"
@@ -100,6 +100,7 @@ dev = [
100
100
  "ruff>=0.8.0",
101
101
  "twine>=6.0.0",
102
102
  "psycopg[binary]>=3.3.2",
103
+ "django-stubs>=6.0.7",
103
104
  ]
104
105
 
105
106
 
@@ -18,7 +18,7 @@ Infrastructure & tooling:
18
18
  - Structured logging with correlation IDs, request metadata binding,
19
19
  and pre-built ``LOGGING`` configuration (structlog)
20
20
  - Audit log export to S3 with export-state tracking and status history
21
- - Cursor-based pagination for Django Ninja APIs
21
+ - Paginated APIs via Django Ninja Extra (``PageNumberPaginationExtra``)
22
22
  - PDF generation via WeasyPrint (``Printer`` class and ``WeasyTemplateView``)
23
23
  - Multi-currency support with rate syncing (BCC, Open Exchange Rates)
24
24
  - Celery app with task auto-discovery and structlog integration
@@ -40,7 +40,7 @@ Other:
40
40
  image validation, bound-request detection
41
41
  """
42
42
 
43
- __version__ = "0.5.0"
43
+ __version__ = "0.5.2"
44
44
 
45
45
  from oxutils.conf import AUDIT_MIDDLEWARE, UTILS_APPS
46
46
  from oxutils.settings import oxi_settings
@@ -9,8 +9,8 @@ from oxutils.models import (
9
9
  )
10
10
 
11
11
  from .enums import CurrencySource
12
+ from .signals import currency_sync_failed, currency_sync_succeeded
12
13
  from .utils import load_rates
13
- from .signals import currency_sync_succeeded, currency_sync_failed
14
14
 
15
15
  logger = structlog.get_logger(__name__)
16
16
 
@@ -20,6 +20,7 @@ AVAILABLES_CURRENCIES = [
20
20
  "AUD",
21
21
  "BIF",
22
22
  "CAD",
23
+ "CDF",
23
24
  "CHF",
24
25
  "CNY",
25
26
  "EUR",
@@ -1,12 +1,10 @@
1
1
  from functools import wraps
2
+
2
3
  import structlog
3
4
  from django.contrib.auth import get_user_model
4
5
  from django.http import HttpRequest
5
-
6
6
  from ninja_jwt.exceptions import InvalidToken
7
7
 
8
-
9
-
10
8
  logger = structlog.getLogger("django")
11
9
  User = get_user_model()
12
10
 
@@ -26,11 +24,13 @@ def load_user(f):
26
24
  # self.request.user will be the complete user object
27
25
  pass
28
26
  """
27
+
29
28
  @wraps(f)
30
29
  def wrapper(self, *args, **kwargs):
31
30
  populate_user(self.context.request)
32
31
  res = f(self, *args, **kwargs)
33
32
  return res
33
+
34
34
  return wrapper
35
35
 
36
36
 
@@ -41,5 +41,5 @@ def populate_user(request: HttpRequest):
41
41
  try:
42
42
  request.user = User.objects.get(oxi_id=request.user.id)
43
43
  except User.DoesNotExist as exc:
44
- logger.exception('user_not_found', oxi_id=request.user.id, message=str(exc))
45
- raise InvalidToken()
44
+ logger.exception("user_not_found", oxi_id=request.user.id, message=str(exc))
45
+ raise InvalidToken() from exc
@@ -1,4 +1,3 @@
1
- from django.conf import settings
2
1
  from django.db import transaction
3
2
 
4
3
  from oxutils.oxiliere.models import BaseTenant
@@ -9,21 +8,28 @@ from oxutils.permissions.utils import assign_role
9
8
 
10
9
  @transaction.atomic
11
10
  def grant_manager_access_to_owners(tenant: BaseTenant):
11
+ """
12
+ Grant **all** configured permissions to every tenant owner.
13
+
14
+ Idempotent — can be called multiple times without creating duplicates.
15
+ Uses :func:`assign_role` which performs an upsert per (user, scope, role).
16
+ """
12
17
  tenant_user_model = get_tenant_user_model()
13
18
  tenant_users = tenant_user_model.objects.select_related("user").filter(
14
19
  tenant=tenant, is_owner=True
15
20
  )
16
21
 
17
- access_scope = settings.ACCESS_MANAGER_SCOPE
18
-
19
- # Vérifier qu'il y a des RoleGrants pour ce scope
20
- role_grants = list(RoleGrant.objects.filter(scope=access_scope))
22
+ role_grants = list(RoleGrant.objects.select_related("role").all())
21
23
 
22
24
  if not role_grants:
23
25
  return
24
26
 
25
27
  for tenant_user in tenant_users:
26
- for grant in role_grants:
28
+ for rg in role_grants:
27
29
  assign_role(
28
- user=tenant_user.user, role=grant.role, scope=grant.scope, by=None, user_group=None
30
+ user=tenant_user.user,
31
+ role=rg.role.slug,
32
+ scope=rg.scope,
33
+ by=None,
34
+ user_group=None,
29
35
  )
@@ -2,43 +2,43 @@ from uuid import UUID
2
2
 
3
3
  from ninja_extra import (
4
4
  api_controller,
5
+ http_delete,
5
6
  http_get,
6
7
  http_put,
7
- http_delete,
8
- )
9
- from ninja_extra.permissions import (
10
- IsAuthenticated,
11
8
  )
12
9
  from ninja_extra.pagination import (
13
- paginate,
14
- PaginatedResponseSchema,
15
10
  PageNumberPaginationExtra,
11
+ PaginatedResponseSchema,
12
+ paginate,
13
+ )
14
+ from ninja_extra.permissions import (
15
+ IsAuthenticated,
16
16
  )
17
+
17
18
  from oxutils.oxiliere.permissions import (
18
19
  IsTenantAdmin,
19
20
  IsTenantOwner,
20
21
  )
22
+
21
23
  from .schemas import (
22
- get_tenant_user_list_schema,
23
- get_tenant_user_detail_schema,
24
- UpdateTenantUserSchema,
25
24
  SetAdminSchema,
26
25
  SetOwnerSchema,
26
+ UpdateTenantUserSchema,
27
+ get_tenant_user_detail_schema,
28
+ get_tenant_user_list_schema,
27
29
  )
28
30
  from .services import TenantUserService
29
31
 
30
-
31
32
  TenantUserListSchema = get_tenant_user_list_schema()
32
33
  TenantUserDetailSchema = get_tenant_user_detail_schema()
33
34
 
34
35
  service = TenantUserService()
35
36
 
36
37
 
37
- @api_controller('/users')
38
+ @api_controller("/users")
38
39
  class UserController:
39
-
40
40
  @http_get(
41
- '',
41
+ "",
42
42
  response=PaginatedResponseSchema[TenantUserListSchema],
43
43
  permissions=[IsAuthenticated, IsTenantAdmin],
44
44
  )
@@ -47,7 +47,7 @@ class UserController:
47
47
  return service.list()
48
48
 
49
49
  @http_get(
50
- '/{user_id}',
50
+ "/{user_id}",
51
51
  response=TenantUserDetailSchema,
52
52
  permissions=[IsAuthenticated, IsTenantAdmin],
53
53
  )
@@ -55,7 +55,7 @@ class UserController:
55
55
  return service.get(user_id)
56
56
 
57
57
  @http_put(
58
- '/{user_id}',
58
+ "/{user_id}",
59
59
  response=TenantUserDetailSchema,
60
60
  permissions=[IsAuthenticated, IsTenantOwner],
61
61
  )
@@ -63,7 +63,7 @@ class UserController:
63
63
  return service.update(user_id, payload.dict(exclude_unset=True))
64
64
 
65
65
  @http_put(
66
- '/{user_id}/set-admin',
66
+ "/{user_id}/set-admin",
67
67
  response=TenantUserDetailSchema,
68
68
  permissions=[IsAuthenticated, IsTenantOwner],
69
69
  )
@@ -71,7 +71,7 @@ class UserController:
71
71
  return service.set_admin(user_id, payload.is_admin)
72
72
 
73
73
  @http_put(
74
- '/{user_id}/set-owner',
74
+ "/{user_id}/set-owner",
75
75
  response=TenantUserDetailSchema,
76
76
  permissions=[IsAuthenticated, IsTenantOwner],
77
77
  )
@@ -79,7 +79,7 @@ class UserController:
79
79
  return service.set_owner(user_id, payload.is_owner)
80
80
 
81
81
  @http_delete(
82
- '/{user_id}',
82
+ "/{user_id}",
83
83
  response={204: None},
84
84
  permissions=[IsAuthenticated, IsTenantOwner],
85
85
  )
@@ -95,7 +95,12 @@ class Command(BaseCommand):
95
95
 
96
96
  with tenant_context(tenant):
97
97
  stats = load_preset()
98
- print(stats)
98
+ self.stdout.write(
99
+ f" Permissions loaded: "
100
+ f"roles +{stats['roles']['created']}/~{stats['roles']['updated']}, "
101
+ f"groups +{stats['groups']['created']}/~{stats['groups']['updated']}, "
102
+ f"role_grants +{stats['role_grants']['created']}/~{stats['role_grants']['updated']}"
103
+ )
99
104
 
100
105
  if created:
101
106
  self.stdout.write(self.style.SUCCESS(f'✓ Superuser lié au tenant système'))
@@ -1,10 +1,10 @@
1
1
  """
2
2
  Oxiliere services — TenantUser management + Tenant lifecycle.
3
3
  """
4
- import structlog
5
- from typing import Optional
4
+
6
5
  from uuid import UUID
7
6
 
7
+ import structlog
8
8
  from django.contrib.auth.models import AbstractBaseUser
9
9
  from django.db import transaction
10
10
  from django.db.models import QuerySet
@@ -19,6 +19,7 @@ logger = structlog.get_logger(__name__)
19
19
 
20
20
  # ── TenantUserService (existing) ────────────────────────────────────
21
21
 
22
+
22
23
  class TenantUserService(BaseService):
23
24
  logger = logger
24
25
 
@@ -98,6 +99,7 @@ class TenantUserService(BaseService):
98
99
 
99
100
  # ── TenantService (new) ─────────────────────────────────────────────
100
101
 
102
+
101
103
  class TenantService:
102
104
  """Thin service layer for tenant lifecycle operations."""
103
105
 
@@ -127,7 +129,9 @@ class TenantService:
127
129
  tenant.save(update_fields=["status", "is_active"])
128
130
 
129
131
  @staticmethod
130
- def add_user(tenant, user: AbstractBaseUser, is_owner: bool = False, is_admin: bool = False) -> None:
132
+ def add_user(
133
+ tenant, user: AbstractBaseUser, is_owner: bool = False, is_admin: bool = False
134
+ ) -> None:
131
135
  tenant.add_user(user, is_owner=is_owner, is_admin=is_admin)
132
136
 
133
137
  @staticmethod
@@ -33,6 +33,7 @@ no hierarchy expansion occurs (actions are treated as independent).
33
33
 
34
34
  from __future__ import annotations
35
35
 
36
+
36
37
  def _get_all_actions() -> dict[str, dict[str, dict]]:
37
38
  """Return all action definitions from ``PERMISSION_PRESET["actions"]``."""
38
39
  from django.conf import settings
@@ -129,10 +130,7 @@ def validate_actions_for_scope(scope: str, actions: list[str]) -> list[str]:
129
130
 
130
131
  invalid = [a for a in actions if a not in valid]
131
132
  if invalid:
132
- raise ValueError(
133
- f"Invalid actions for scope '{scope}': {invalid}. "
134
- f"Valid actions: {valid}"
135
- )
133
+ raise ValueError(f"Invalid actions for scope '{scope}': {invalid}. Valid actions: {valid}")
136
134
  return actions
137
135
 
138
136
 
@@ -172,7 +170,4 @@ def get_scope_actions_labels(scope: str) -> dict[str, str]:
172
170
  Returns:
173
171
  Dict mapping action key → translated label.
174
172
  """
175
- return {
176
- action: get_action_label(scope, action)
177
- for action in get_valid_actions(scope)
178
- }
173
+ return {action: get_action_label(scope, action) for action in get_valid_actions(scope)}
@@ -1,33 +1,32 @@
1
1
  from django.conf import settings
2
2
 
3
-
4
-
5
- CACHE_CHECK_PERMISSION = getattr(settings, 'CACHE_CHECK_PERMISSION', False)
3
+ CACHE_CHECK_PERMISSION = getattr(settings, "CACHE_CHECK_PERMISSION", False)
6
4
 
7
5
  if CACHE_CHECK_PERMISSION:
8
6
  from cacheops import cached_as
7
+
9
8
  from .models import Grant
10
- from .utils import check, any_action_check, any_permission_check
9
+ from .utils import any_action_check, any_permission_check, check
11
10
 
12
- @cached_as(Grant, timeout=60*15)
13
- def cache_check(user, scope, actions, role = None, **context):
11
+ @cached_as(Grant, timeout=60 * 15)
12
+ def cache_check(user, scope, actions, role=None, **context):
14
13
  return check(user, scope, actions, role=role, **context)
15
-
16
- @cached_as(Grant, timeout=60*15)
17
- def cache_any_action_check(user, scope, required, role = None, **context):
14
+
15
+ @cached_as(Grant, timeout=60 * 15)
16
+ def cache_any_action_check(user, scope, required, role=None, **context):
18
17
  return any_action_check(user, scope, required, role=role, **context)
19
-
20
- @cached_as(Grant, timeout=60*15)
18
+
19
+ @cached_as(Grant, timeout=60 * 15)
21
20
  def cache_any_permission_check(user, *str_perms):
22
21
  return any_permission_check(user, *str_perms)
23
22
  else:
24
- from .utils import check, any_action_check, any_permission_check
23
+ from .utils import any_action_check, any_permission_check, check
25
24
 
26
- def cache_check(user, scope, actions, role = None, **context):
25
+ def cache_check(user, scope, actions, role=None, **context):
27
26
  return check(user, scope, actions, role=role, **context)
28
-
29
- def cache_any_action_check(user, scope, required, role = None, **context):
27
+
28
+ def cache_any_action_check(user, scope, required, role=None, **context):
30
29
  return any_action_check(user, scope, required, role=role, **context)
31
-
30
+
32
31
  def cache_any_permission_check(user, *str_perms):
33
32
  return any_permission_check(user, *str_perms)
@@ -23,7 +23,7 @@ Example configuration in settings.py:
23
23
 
24
24
  PERMISSION_PRESET = {
25
25
  "roles": [...],
26
- "group": [...],
26
+ "groups": [...],
27
27
  "role_grants": [...]
28
28
  }
29
29
  """
@@ -134,14 +134,14 @@ def check_permission_settings(app_configs, **kwargs):
134
134
  )
135
135
  else:
136
136
  # Check required keys
137
- required_keys = ["roles", "group", "role_grants"]
137
+ required_keys = ["roles", "groups", "role_grants"]
138
138
  for key in required_keys:
139
139
  if key not in preset:
140
140
  errors.append(
141
141
  Error(
142
142
  f"PERMISSION_PRESET is missing required key: {key}",
143
143
  hint=f'Add "{key}" key to PERMISSION_PRESET',
144
- id=f"permissions.E007",
144
+ id="permissions.E007",
145
145
  )
146
146
  )
147
147
 
@@ -206,15 +206,15 @@ def check_permission_settings(app_configs, **kwargs):
206
206
  and settings.ACCESS_MANAGER_GROUP is not None
207
207
  and hasattr(settings, "PERMISSION_PRESET")
208
208
  and isinstance(settings.PERMISSION_PRESET, dict)
209
- and "group" in settings.PERMISSION_PRESET
209
+ and "groups" in settings.PERMISSION_PRESET
210
210
  ):
211
- group_slugs = [g.get("slug") for g in settings.PERMISSION_PRESET.get("group", [])]
211
+ group_slugs = [g.get("slug") for g in settings.PERMISSION_PRESET.get("groups", [])]
212
212
 
213
213
  if settings.ACCESS_MANAGER_GROUP not in group_slugs:
214
214
  errors.append(
215
215
  Error(
216
216
  f'ACCESS_MANAGER_GROUP "{settings.ACCESS_MANAGER_GROUP}" is not in PERMISSION_PRESET groups',
217
- hint=f'Add a group with slug "{settings.ACCESS_MANAGER_GROUP}" to PERMISSION_PRESET["group"]',
217
+ hint=f'Add a group with slug "{settings.ACCESS_MANAGER_GROUP}" to PERMISSION_PRESET["groups"]',
218
218
  id="permissions.E009",
219
219
  )
220
220
  )
@@ -257,7 +257,7 @@ def check_permission_settings(app_configs, **kwargs):
257
257
  )
258
258
  )
259
259
 
260
- for group_data in settings.PERMISSION_PRESET.get("group", []):
260
+ for group_data in settings.PERMISSION_PRESET.get("groups", []):
261
261
  app = group_data.get("app")
262
262
  if app and app not in apps_list:
263
263
  errors.append(
@@ -268,17 +268,12 @@ def check_permission_settings(app_configs, **kwargs):
268
268
  )
269
269
  )
270
270
 
271
- # Cross-validation: scope ownership — each scope in actions must be unique across apps
271
+ # Cross-validation: scope ownership — each scope in actions must be unique across apps.
272
+ # (Conflicts between settings.PERMISSION_PRESET and app presets are already caught
273
+ # by register_preset() which raises ImproperlyConfigured at startup.)
272
274
  if hasattr(settings, "PERMISSION_PRESET") and isinstance(settings.PERMISSION_PRESET, dict):
273
275
  scope_owners: dict[str, str] = {}
274
276
 
275
- # Collect scopes from the base preset (settings.py)
276
- base_actions = settings.PERMISSION_PRESET.get("actions", {})
277
- if isinstance(base_actions, dict):
278
- for scope in base_actions:
279
- scope_owners[scope] = "settings.PERMISSION_PRESET"
280
-
281
- # Collect scopes from discovered app presets
282
277
  from oxutils.permissions.presets import discover_app_presets
283
278
 
284
279
  for preset in discover_app_presets():
@@ -290,13 +285,10 @@ def check_permission_settings(app_configs, **kwargs):
290
285
  if scope in scope_owners:
291
286
  errors.append(
292
287
  Error(
293
- f'Scope "{scope}" is already owned by "{scope_owners[scope]}". '
294
- f'App "{app_label}" cannot redefine it.',
295
- hint=(
296
- f"Each scope must be owned by exactly one app. "
297
- f'Remove the scope "{scope}" from app "{app_label}" '
298
- f"or use a different scope name."
299
- ),
288
+ f'Scope "{scope}" is defined in both '
289
+ f'"{scope_owners[scope]}" and "{app_label}". '
290
+ f'Each scope must be owned by exactly one app.',
291
+ hint=f'Remove the scope "{scope}" from one of the apps.',
300
292
  id="permissions.E022",
301
293
  )
302
294
  )
@@ -316,7 +308,7 @@ def check_permission_settings(app_configs, **kwargs):
316
308
  break
317
309
 
318
310
  if not has_app_attr:
319
- for group_data in settings.PERMISSION_PRESET.get("group", []):
311
+ for group_data in settings.PERMISSION_PRESET.get("groups", []):
320
312
  if group_data.get("app"):
321
313
  has_app_attr = True
322
314
  break
@@ -384,7 +376,7 @@ def check_permission_settings(app_configs, **kwargs):
384
376
  )
385
377
  continue
386
378
  try:
387
- cls = import_string(path)
379
+ import_string(path)
388
380
  except ImportError:
389
381
  errors.append(
390
382
  Error(
@@ -1,60 +1,70 @@
1
1
  from django.utils.translation import gettext_lazy as _
2
+
2
3
  from oxutils.exceptions import (
3
- APIException,
4
- NotFoundException,
5
- ValidationException,
6
4
  DuplicateEntryException,
5
+ ExceptionCode,
6
+ NotFoundException,
7
7
  PermissionDeniedException,
8
- ExceptionCode
8
+ ValidationException,
9
9
  )
10
10
 
11
11
 
12
12
  class RoleNotFoundException(NotFoundException):
13
13
  """Exception levée quand un rôle n'est pas trouvé."""
14
- default_detail = _('The requested role does not exist')
14
+
15
+ default_detail = _("The requested role does not exist")
15
16
 
16
17
 
17
18
  class GroupNotFoundException(NotFoundException):
18
19
  """Exception levée quand un groupe n'est pas trouvé."""
19
- default_detail = _('The requested group does not exist')
20
+
21
+ default_detail = _("The requested group does not exist")
20
22
 
21
23
 
22
24
  class GrantNotFoundException(NotFoundException):
23
25
  """Exception levée quand un grant n'est pas trouvé."""
24
- default_detail = _('The requested grant does not exist')
26
+
27
+ default_detail = _("The requested grant does not exist")
25
28
 
26
29
 
27
30
  class RoleGrantNotFoundException(NotFoundException):
28
31
  """Exception levée quand un role grant n'est pas trouvé."""
29
- default_detail = _('The requested role grant does not exist')
32
+
33
+ default_detail = _("The requested role grant does not exist")
30
34
 
31
35
 
32
36
  class RoleAlreadyAssignedException(DuplicateEntryException):
33
37
  """Exception levée quand un rôle est déjà assigné à un utilisateur."""
34
- default_detail = _('This role is already assigned to the user')
38
+
39
+ default_detail = _("This role is already assigned to the user")
35
40
 
36
41
 
37
42
  class GroupAlreadyAssignedException(DuplicateEntryException):
38
43
  """Exception levée quand un groupe est déjà assigné à un utilisateur."""
39
- default_detail = _('This group is already assigned to the user')
44
+
45
+ default_detail = _("This group is already assigned to the user")
40
46
 
41
47
 
42
48
  class InvalidActionsException(ValidationException):
43
49
  """Exception levée quand des actions invalides sont fournies."""
44
- default_detail = _('The provided actions are invalid')
50
+
51
+ default_detail = _("The provided actions are invalid")
45
52
 
46
53
 
47
54
  class InsufficientPermissionsException(PermissionDeniedException):
48
55
  """Exception levée quand l'utilisateur n'a pas les permissions suffisantes."""
56
+
49
57
  default_code = ExceptionCode.INSUFFICIENT_PERMISSIONS
50
- default_detail = _('Insufficient permissions to perform this action')
58
+ default_detail = _("Insufficient permissions to perform this action")
51
59
 
52
60
 
53
61
  class RoleGrantConflictException(DuplicateEntryException):
54
62
  """Exception levée quand un role grant existe déjà pour ce rôle et scope."""
55
- default_detail = _('A role grant already exists for this role and scope')
63
+
64
+ default_detail = _("A role grant already exists for this role and scope")
56
65
 
57
66
 
58
67
  class GrantConflictException(DuplicateEntryException):
59
68
  """Exception levée quand un grant existe déjà pour cet utilisateur et scope."""
60
- default_detail = _('A grant already exists for this user and scope')
69
+
70
+ default_detail = _("A grant already exists for this user and scope")