oxutils 0.4.0__tar.gz → 0.4.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 (214) hide show
  1. {oxutils-0.4.0 → oxutils-0.4.2}/PKG-INFO +1 -1
  2. {oxutils-0.4.0 → oxutils-0.4.2}/pyproject.toml +2 -1
  3. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/__init__.py +1 -1
  4. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/cacheops.py +1 -1
  5. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/middleware.py +20 -3
  6. oxutils-0.4.2/src/oxutils/permissions/migrations/0009_grant_is_active.py +18 -0
  7. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/models.py +1 -0
  8. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/perms.py +40 -45
  9. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/schemas.py +50 -28
  10. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/utils.py +46 -17
  11. oxutils-0.4.0/src/oxutils/audit/locale/fr/LC_MESSAGES/django.mo +0 -0
  12. oxutils-0.4.0/src/oxutils/oxiliere/locale/fr/LC_MESSAGES/django.mo +0 -0
  13. oxutils-0.4.0/src/oxutils/permissions/locale/fr/LC_MESSAGES/django.mo +0 -0
  14. oxutils-0.4.0/src/oxutils/users/locale/fr/LC_MESSAGES/django.mo +0 -0
  15. {oxutils-0.4.0 → oxutils-0.4.2}/README.md +0 -0
  16. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/apps.py +0 -0
  17. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/__init__.py +0 -0
  18. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/apps.py +0 -0
  19. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/export.py +0 -0
  20. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/locale/fr/LC_MESSAGES/django.po +0 -0
  21. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/masks.py +0 -0
  22. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/migrations/0001_initial.py +0 -0
  23. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/migrations/__init__.py +0 -0
  24. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/models.py +0 -0
  25. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/settings.py +0 -0
  26. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/audit/utils.py +0 -0
  27. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/__init__.py +0 -0
  28. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/adapter.py +0 -0
  29. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/admin.py +0 -0
  30. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/app_settings.py +0 -0
  31. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/apps.py +0 -0
  32. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/constants.py +0 -0
  33. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/controllers.py +0 -0
  34. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/emails/__init__.py +0 -0
  35. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/emails/controllers.py +0 -0
  36. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/emails/schemas.py +0 -0
  37. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/emails/services.py +0 -0
  38. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/exceptions.py +0 -0
  39. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/__init__.py +0 -0
  40. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/backend.py +0 -0
  41. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/controllers.py +0 -0
  42. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/models.py +0 -0
  43. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/schemas.py +0 -0
  44. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/invitations/tokens.py +0 -0
  45. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/__init__.py +0 -0
  46. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/adapter.py +0 -0
  47. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/base/__init__.py +0 -0
  48. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/base/controllers.py +0 -0
  49. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/base/schemas.py +0 -0
  50. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/recovery_codes/__init__.py +0 -0
  51. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/recovery_codes/controllers.py +0 -0
  52. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/recovery_codes/flows.py +0 -0
  53. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/recovery_codes/schemas.py +0 -0
  54. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/recovery_codes/services.py +0 -0
  55. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/__ini__.py +0 -0
  56. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/controllers.py +0 -0
  57. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/flows.py +0 -0
  58. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/permissions.py +0 -0
  59. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/schemas.py +0 -0
  60. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/totp/services.py +0 -0
  61. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mfa/utils.py +0 -0
  62. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/migrations/0001_initial.py +0 -0
  63. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/migrations/__init__.py +0 -0
  64. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/mixins.py +0 -0
  65. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/models.py +0 -0
  66. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/password_reset/__init__.py +0 -0
  67. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/password_reset/controllers.py +0 -0
  68. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/password_reset/models.py +0 -0
  69. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/password_reset/permissions.py +0 -0
  70. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/password_reset/schemas.py +0 -0
  71. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/registration/__init__.py +0 -0
  72. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/registration/controllers.py +0 -0
  73. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/registration/schemas.py +0 -0
  74. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/schemas.py +0 -0
  75. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/sessions/__init__.py +0 -0
  76. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/sessions/controllers.py +0 -0
  77. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/sessions/schemas.py +0 -0
  78. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/signals.py +0 -0
  79. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/templatetags/__init__.py +0 -0
  80. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/templatetags/spa_urls.py +0 -0
  81. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/__init__.py +0 -0
  82. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/app_settings.py +0 -0
  83. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/models.py +0 -0
  84. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/schemas.py +0 -0
  85. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/tokens.py +0 -0
  86. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/tokens/utils.py +0 -0
  87. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/auth/utils.py +0 -0
  88. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/celery/__init__.py +0 -0
  89. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/celery/base.py +0 -0
  90. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/celery/settings.py +0 -0
  91. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/conf.py +0 -0
  92. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/constants.py +0 -0
  93. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/context/__init__.py +0 -0
  94. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/context/site_name_processor.py +0 -0
  95. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/__init__.py +0 -0
  96. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/admin.py +0 -0
  97. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/apps.py +0 -0
  98. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/caches.py +0 -0
  99. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/controllers.py +0 -0
  100. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/enums.py +0 -0
  101. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/management/__init__.py +0 -0
  102. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/management/commands/__init__.py +0 -0
  103. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/management/commands/sync_currency.py +0 -0
  104. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/migrations/0001_initial.py +0 -0
  105. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/migrations/__init__.py +0 -0
  106. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/models.py +0 -0
  107. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/schemas.py +0 -0
  108. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/signals.py +0 -0
  109. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/tests.py +0 -0
  110. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/currency/utils.py +0 -0
  111. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/enums/__init__.py +0 -0
  112. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/enums/audit.py +0 -0
  113. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/enums/invoices.py +0 -0
  114. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/exceptions.py +0 -0
  115. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/functions.py +0 -0
  116. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/__init__.py +0 -0
  117. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/auth.py +0 -0
  118. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/middleware.py +0 -0
  119. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/models.py +0 -0
  120. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/tokens.py +0 -0
  121. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/jwt/utils.py +0 -0
  122. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/logger/__init__.py +0 -0
  123. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/logger/receivers.py +0 -0
  124. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/logger/settings.py +0 -0
  125. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/mixins/__init__.py +0 -0
  126. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/mixins/base.py +0 -0
  127. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/mixins/schemas.py +0 -0
  128. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/mixins/services.py +0 -0
  129. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/__init__.py +0 -0
  130. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/base.py +0 -0
  131. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/billing.py +0 -0
  132. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/change_tracker.py +0 -0
  133. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/fields.py +0 -0
  134. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/models/invoice.py +0 -0
  135. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/__init__.py +0 -0
  136. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/admin.py +0 -0
  137. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/apps.py +0 -0
  138. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/authorization.py +0 -0
  139. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/caches.py +0 -0
  140. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/checks.py +0 -0
  141. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/constants.py +0 -0
  142. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/context.py +0 -0
  143. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/controllers.py +0 -0
  144. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/enums.py +0 -0
  145. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/exceptions.py +0 -0
  146. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/locale/fr/LC_MESSAGES/django.po +0 -0
  147. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/management/__init__.py +0 -0
  148. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/management/commands/__init__.py +0 -0
  149. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/management/commands/grant_tenant_owners.py +0 -0
  150. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/management/commands/init_oxiliere_system.py +0 -0
  151. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/migrations/__init__.py +0 -0
  152. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/models.py +0 -0
  153. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/permissions.py +0 -0
  154. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/schemas.py +0 -0
  155. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/services.py +0 -0
  156. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/settings.py +0 -0
  157. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/signals.py +0 -0
  158. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/tests.py +0 -0
  159. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/oxiliere/utils.py +0 -0
  160. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pagination/__init__.py +0 -0
  161. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pagination/cursor.py +0 -0
  162. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pdf/__init__.py +0 -0
  163. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pdf/printer.py +0 -0
  164. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pdf/utils.py +0 -0
  165. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/pdf/views.py +0 -0
  166. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/__init__.py +0 -0
  167. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/actions.py +0 -0
  168. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/admin.py +0 -0
  169. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/apps.py +0 -0
  170. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/caches.py +0 -0
  171. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/checks.py +0 -0
  172. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/constants.py +0 -0
  173. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/controllers.py +0 -0
  174. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/exceptions.py +0 -0
  175. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/locale/fr/LC_MESSAGES/django.po +0 -0
  176. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/management/__init__.py +0 -0
  177. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/management/commands/__init__.py +0 -0
  178. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/management/commands/load_permission_preset.py +0 -0
  179. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0001_initial.py +0 -0
  180. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0002_alter_grant_role.py +0 -0
  181. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +0 -0
  182. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0004_group_app_group_permissions_app_9a9924_idx.py +0 -0
  183. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0005_role_app.py +0 -0
  184. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0006_alter_rolegrant_options_and_more.py +0 -0
  185. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0007_grant_locked_alter_grant_role_and_more.py +0 -0
  186. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/0008_remove_grant_unique_user_scope_role_and_more.py +0 -0
  187. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/migrations/__init__.py +0 -0
  188. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/queryset.py +0 -0
  189. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/services.py +0 -0
  190. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/permissions/tests.py +0 -0
  191. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/py.typed +0 -0
  192. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/s3.py +0 -0
  193. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/settings.py +0 -0
  194. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/account/email/base_message.txt +0 -0
  195. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/email/password/reset_email_message.html +0 -0
  196. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/email/password/reset_email_message.txt +0 -0
  197. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/email/password/reset_email_subject.txt +0 -0
  198. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/email/signup/email_message.html +0 -0
  199. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/email/signup/email_subject.txt +0 -0
  200. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/templates/verified.html +0 -0
  201. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/types.py +0 -0
  202. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/__init__.py +0 -0
  203. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/admin.py +0 -0
  204. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/apps.py +0 -0
  205. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/locale/fr/LC_MESSAGES/django.po +0 -0
  206. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/migrations/0001_initial.py +0 -0
  207. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +0 -0
  208. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/migrations/0003_user_photo.py +0 -0
  209. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/migrations/0004_alter_user_options.py +0 -0
  210. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/migrations/__init__.py +0 -0
  211. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/models.py +0 -0
  212. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/tests.py +0 -0
  213. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/users/utils.py +0 -0
  214. {oxutils-0.4.0 → oxutils-0.4.2}/src/oxutils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxutils
3
- Version: 0.4.0
3
+ Version: 0.4.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.4.0"
3
+ version = "0.4.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"
@@ -98,6 +98,7 @@ dev = [
98
98
  "coverage>=7.4.0",
99
99
  "pillow>=12.0.0",
100
100
  "ruff>=0.8.0",
101
+ "twine>=6.0.0",
101
102
  "psycopg[binary]>=3.3.2",
102
103
  ]
103
104
 
@@ -15,7 +15,7 @@ This package provides:
15
15
  - Custom exceptions, enums, and type definitions
16
16
  """
17
17
 
18
- __version__ = "0.4.0"
18
+ __version__ = "0.4.2"
19
19
 
20
20
  from oxutils.conf import AUDIT_MIDDLEWARE, UTILS_APPS
21
21
  from oxutils.settings import oxi_settings
@@ -34,7 +34,7 @@ def get_cached_tenant_token(oxi_id: str, user_id: str):
34
34
  raise ObjectDoesNotExist(f"tenant not found: {oxi_id}") from ex
35
35
 
36
36
  try:
37
- tenant_user = tenant.users.select_related("user").get(user__pk=user_id)
37
+ tenant_user = tenant.users.select_related("user").get(user__pk=user_id, status="active")
38
38
  except (ObjectDoesNotExist, ValueError) as ex:
39
39
  raise ObjectDoesNotExist(f"tenant_user not found: {oxi_id}/{user_id}") from ex
40
40
 
@@ -55,7 +55,7 @@ class TenantMainMiddleware(MiddlewareMixin):
55
55
  return None
56
56
 
57
57
  try:
58
- return tenant.users.select_related("user").get(user__pk=user.id)
58
+ return tenant.users.select_related("user").get(user__pk=user.id, status="active")
59
59
  except ObjectDoesNotExist as exc:
60
60
  logger.error("tenant_user_not_found", tenant_id=tenant.id, user_id=user.id, exc_info=exc)
61
61
  if raise_exception:
@@ -99,8 +99,25 @@ class TenantMainMiddleware(MiddlewareMixin):
99
99
 
100
100
  return HttpResponseBadRequest("Missing X-Organization-ID header")
101
101
  else:
102
- # oxi_id present but no authenticated user
103
- return self.no_tenant_found(request, oxi_id)
102
+ # oxi_id present but no authenticated user → fall back to system tenant
103
+ # (same behaviour as "no org header") — previously this raised Http404,
104
+ # which broke every route (including public ones) when the JWT token
105
+ # expired but the front-end still sent X-Organization-ID.
106
+ try:
107
+ from oxutils.oxiliere.caches import get_system_tenant
108
+
109
+ tenant = get_system_tenant()
110
+ # don't try to attach a tenant-user — the user is anonymous anyway
111
+ tenant.user = None
112
+ except Exception as e:
113
+ logger.error(
114
+ "system_tenant_not_found",
115
+ oxi_id=oxi_id,
116
+ error=str(e),
117
+ )
118
+ from django.http import HttpResponseBadRequest
119
+
120
+ return HttpResponseBadRequest("Missing X-Organization-ID header")
104
121
 
105
122
  # ── Status guards ─────────────────────────────────────────────
106
123
  if tenant.is_deleted or not tenant.is_active:
@@ -0,0 +1,18 @@
1
+ # Generated by Django 5.2.9 on 2026-06-29 14:25
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('permissions', '0008_remove_grant_unique_user_scope_role_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='grant',
15
+ name='is_active',
16
+ field=models.BooleanField(default=True),
17
+ ),
18
+ ]
@@ -148,6 +148,7 @@ class Grant(TimestampMixin):
148
148
  scope = models.CharField(max_length=100)
149
149
  actions = ArrayField(models.CharField(max_length=5))
150
150
  context = models.JSONField(default=dict, blank=True)
151
+ is_active = models.BooleanField(default=True)
151
152
 
152
153
  class Meta:
153
154
  constraints = [
@@ -1,25 +1,25 @@
1
1
  from typing import Optional
2
+
2
3
  from django.conf import settings
3
4
  from django.core.exceptions import ImproperlyConfigured
4
5
  from django.http import HttpRequest
5
- from ninja_extra.permissions import BasePermission
6
6
  from ninja_extra.controllers import ControllerBase
7
+ from ninja_extra.permissions import BasePermission
7
8
 
8
9
  from oxutils.permissions.utils import str_check
9
10
 
10
11
 
11
-
12
12
  class ScopePermission(BasePermission):
13
13
  """
14
14
  Permission class for checking user permissions using the string format.
15
-
15
+
16
16
  Format: "<scope>:<actions>" or "<scope>:<actions>:<role>?key=value"
17
-
17
+
18
18
  Example:
19
19
  @api_controller('/articles', permissions=[ScopePermission('articles:w')])
20
20
  class ArticleController:
21
21
  pass
22
-
22
+
23
23
  @api_controller('/articles', permissions=[ScopePermission('articles:w:editor')])
24
24
  class EditorArticleController:
25
25
  pass
@@ -28,7 +28,7 @@ class ScopePermission(BasePermission):
28
28
  def __init__(self, perm: str, ctx: Optional[dict] = None):
29
29
  """
30
30
  Initialize the permission checker.
31
-
31
+
32
32
  Args:
33
33
  perm: Permission string in format "<scope>:<actions>" or "<scope>:<actions>:<role>?context"
34
34
  """
@@ -38,11 +38,11 @@ class ScopePermission(BasePermission):
38
38
  def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
39
39
  """
40
40
  Check if the user has the required permission.
41
-
41
+
42
42
  Args:
43
43
  request: HTTP request object
44
44
  controller: Controller instance
45
-
45
+
46
46
  Returns:
47
47
  True if user has permission, False otherwise
48
48
  """
@@ -52,10 +52,10 @@ class ScopePermission(BasePermission):
52
52
  class ScopeAnyPermission(BasePermission):
53
53
  """
54
54
  Permission class for checking if user has at least one of multiple permissions.
55
-
55
+
56
56
  Vérifie si l'utilisateur possède au moins une des permissions fournies.
57
57
  Utilise any_permission_check pour une vérification optimisée en une seule requête.
58
-
58
+
59
59
  Example:
60
60
  @api_controller('/articles', permissions=[
61
61
  ScopeAnyPermission('articles:r', 'articles:w:editor', 'articles:d:admin')
@@ -68,7 +68,7 @@ class ScopeAnyPermission(BasePermission):
68
68
  def __init__(self, *perms: str):
69
69
  """
70
70
  Initialize the permission checker with multiple permission strings.
71
-
71
+
72
72
  Args:
73
73
  *perms: Variable number of permission strings in format "<scope>:<actions>" or "<scope>:<actions>:<role>?context"
74
74
  """
@@ -79,25 +79,26 @@ class ScopeAnyPermission(BasePermission):
79
79
  def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
80
80
  """
81
81
  Check if the user has at least one of the required permissions.
82
-
82
+
83
83
  Args:
84
84
  request: HTTP request object
85
85
  controller: Controller instance
86
-
86
+
87
87
  Returns:
88
88
  True if user has at least one permission, False otherwise
89
89
  """
90
90
  from oxutils.permissions.caches import cache_any_permission_check
91
+
91
92
  return cache_any_permission_check(request.user, *self.perms)
92
93
 
93
94
 
94
95
  class ScopeAnyActionPermission(BasePermission):
95
96
  """
96
97
  Permission class for checking if user has at least one of multiple actions on a scope.
97
-
98
+
98
99
  Vérifie si l'utilisateur possède au moins une des actions requises pour un scope donné.
99
100
  La chaîne d'actions contient plusieurs actions dont au moins une est requise.
100
-
101
+
101
102
  Example:
102
103
  @api_controller('/articles', permissions=[
103
104
  ScopeAnyActionPermission('articles:rwd')
@@ -105,7 +106,7 @@ class ScopeAnyActionPermission(BasePermission):
105
106
  class ArticleController:
106
107
  # User needs read OR write OR delete access on articles
107
108
  pass
108
-
109
+
109
110
  @api_controller('/invoices', permissions=[
110
111
  ScopeAnyActionPermission('invoices:rw:accountant')
111
112
  ])
@@ -117,7 +118,7 @@ class ScopeAnyActionPermission(BasePermission):
117
118
  def __init__(self, perm: str, ctx: Optional[dict] = None):
118
119
  """
119
120
  Initialize the permission checker with a permission string.
120
-
121
+
121
122
  Args:
122
123
  perm: Permission string in format "<scope>:<actions>" or "<scope>:<actions>:<role>?context"
123
124
  where actions contains multiple characters (e.g., 'rwd' for read OR write OR delete)
@@ -125,82 +126,76 @@ class ScopeAnyActionPermission(BasePermission):
125
126
  """
126
127
  if not perm:
127
128
  raise ValueError("Permission string must be provided")
128
-
129
+
129
130
  self.perm = perm
130
- self.ctx = ctx if ctx else dict()
131
+ self.ctx = ctx if ctx else {}
131
132
 
132
133
  def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
133
134
  """
134
135
  Check if the user has at least one of the required actions.
135
-
136
+
136
137
  Args:
137
138
  request: HTTP request object
138
139
  controller: Controller instance
139
-
140
+
140
141
  Returns:
141
142
  True if user has at least one action, False otherwise
142
143
  """
143
144
  from oxutils.permissions.caches import cache_any_action_check
144
145
  from oxutils.permissions.utils import parse_permission
145
-
146
+
146
147
  scope, actions, role, query_context = parse_permission(self.perm)
147
148
  final_context = {**query_context, **self.ctx}
148
-
149
- return cache_any_action_check(
150
- request.user,
151
- scope,
152
- actions,
153
- role=role,
154
- **final_context
155
- )
149
+
150
+ return cache_any_action_check(request.user, scope, actions, role=role, **final_context)
156
151
 
157
152
 
158
153
  def access_manager(actions: str):
159
154
  """
160
155
  Factory function for creating ScopePermission instances for access manager.
161
-
156
+
162
157
  Builds a permission string from settings:
163
158
  - ACCESS_MANAGER_SCOPE: The scope to check
164
159
  - ACCESS_MANAGER_GROUP: Optional group for UserGroup assignment (used in authorization)
165
160
  - ACCESS_MANAGER_ROLE: Optional role filter for permission checks
166
161
  - ACCESS_MANAGER_CONTEXT: Optional context dict converted to query params
167
-
162
+
168
163
  Args:
169
164
  actions: Actions required (e.g., 'r', 'rw', 'rwd')
170
-
165
+
171
166
  Returns:
172
167
  ScopePermission instance configured with access manager settings
173
-
168
+
174
169
  Raises:
175
170
  ImproperlyConfigured: If required settings are missing
176
-
171
+
177
172
  Example:
178
173
  @api_controller('/access', permissions=[access_manager('w')])
179
174
  class AccessController:
180
175
  pass
181
176
  """
182
177
  # Validate required settings
183
- if not hasattr(settings, 'ACCESS_MANAGER_SCOPE'):
178
+ if not hasattr(settings, "ACCESS_MANAGER_SCOPE"):
184
179
  raise ImproperlyConfigured(
185
- 'ACCESS_MANAGER_SCOPE is not defined. '
180
+ "ACCESS_MANAGER_SCOPE is not defined. "
186
181
  'Add ACCESS_MANAGER_SCOPE = "access" to your settings.'
187
182
  )
188
-
183
+
189
184
  # Build base permission string: scope:actions
190
185
  perm = f"{settings.ACCESS_MANAGER_SCOPE}:{actions}"
191
-
186
+
192
187
  # Add role if defined and not None
193
- if hasattr(settings, 'ACCESS_MANAGER_ROLE') and settings.ACCESS_MANAGER_ROLE is not None:
188
+ if hasattr(settings, "ACCESS_MANAGER_ROLE") and settings.ACCESS_MANAGER_ROLE is not None:
194
189
  perm += f":{settings.ACCESS_MANAGER_ROLE}"
195
-
190
+
196
191
  # Get context if defined and not empty
197
192
  context = {}
198
- if hasattr(settings, 'ACCESS_MANAGER_CONTEXT') and settings.ACCESS_MANAGER_CONTEXT:
193
+ if hasattr(settings, "ACCESS_MANAGER_CONTEXT") and settings.ACCESS_MANAGER_CONTEXT:
199
194
  context = settings.ACCESS_MANAGER_CONTEXT
200
195
  if not isinstance(context, dict):
201
196
  raise ImproperlyConfigured(
202
- 'ACCESS_MANAGER_CONTEXT must be a dictionary. '
203
- f'Got {type(context).__name__} instead.'
197
+ "ACCESS_MANAGER_CONTEXT must be a dictionary. "
198
+ f"Got {type(context).__name__} instead."
204
199
  )
205
-
200
+
206
201
  return ScopePermission(perm, context)
@@ -1,36 +1,35 @@
1
- from typing import Any, Optional
2
1
  from datetime import datetime
2
+ from typing import Any, Optional
3
3
  from uuid import UUID
4
+
4
5
  from django.conf import settings
5
6
  from ninja import Schema
6
- from oxutils.oxiliere.schemas import UserSchema
7
7
  from pydantic import field_validator
8
8
 
9
+ from oxutils.oxiliere.schemas import UserSchema
10
+
9
11
  from .actions import ACTIONS
10
12
 
11
13
 
12
14
  def validate_actions_list(actions: list[str]) -> list[str]:
13
15
  """
14
16
  Valide qu'une liste d'actions contient uniquement des actions valides.
15
-
17
+
16
18
  Args:
17
19
  actions: Liste des actions à valider
18
-
20
+
19
21
  Returns:
20
22
  La liste d'actions si valide
21
-
23
+
22
24
  Raises:
23
25
  ValueError: Si des actions invalides sont présentes
24
26
  """
25
27
  if not actions:
26
28
  raise ValueError("Les actions ne peuvent pas être vides")
27
-
29
+
28
30
  invalid_actions = [a for a in actions if a not in ACTIONS]
29
31
  if invalid_actions:
30
- raise ValueError(
31
- f"Actions invalides: {invalid_actions}. "
32
- f"Actions valides: {ACTIONS}"
33
- )
32
+ raise ValueError(f"Actions invalides: {invalid_actions}. Actions valides: {ACTIONS}")
34
33
  return actions
35
34
 
36
35
 
@@ -38,6 +37,7 @@ class RoleSchema(Schema):
38
37
  """
39
38
  Schéma pour un rôle.
40
39
  """
40
+
41
41
  slug: str
42
42
  name: str
43
43
  created_at: datetime
@@ -51,6 +51,7 @@ class RoleSimpleSchema(Schema):
51
51
  """
52
52
  Schéma pour un rôle.
53
53
  """
54
+
54
55
  slug: str
55
56
  name: str
56
57
 
@@ -62,6 +63,7 @@ class RoleCreateSchema(Schema):
62
63
  """
63
64
  Schéma pour la création d'un rôle.
64
65
  """
66
+
65
67
  slug: str
66
68
  name: str
67
69
 
@@ -70,6 +72,7 @@ class RoleUpdateSchema(Schema):
70
72
  """
71
73
  Schéma pour la mise à jour d'un rôle.
72
74
  """
75
+
73
76
  name: Optional[str] = None
74
77
 
75
78
 
@@ -77,6 +80,7 @@ class GroupSchema(Schema):
77
80
  """
78
81
  Schéma pour un groupe.
79
82
  """
83
+
80
84
  slug: str
81
85
  name: str
82
86
  app: Optional[str] = None
@@ -99,6 +103,7 @@ class GroupCreateSchema(Schema):
99
103
  """
100
104
  Schéma pour la création d'un groupe.
101
105
  """
106
+
102
107
  name: str
103
108
  app: Optional[str] = None
104
109
  roles: list[str] = []
@@ -108,6 +113,7 @@ class GroupUpdateSchema(Schema):
108
113
  """
109
114
  Schéma pour la mise à jour d'un groupe.
110
115
  """
116
+
111
117
  name: Optional[str] = None
112
118
  roles: Optional[list[str]] = None
113
119
 
@@ -116,6 +122,7 @@ class GroupMemberSchema(Schema):
116
122
  """
117
123
  Schéma pour un membre d'un groupe.
118
124
  """
125
+
119
126
  user: UserSchema
120
127
  group_id: str
121
128
  created_at: Optional[datetime] = None
@@ -125,6 +132,7 @@ class RoleGrantSchema(Schema):
125
132
  """
126
133
  Schéma pour un role grant.
127
134
  """
135
+
128
136
  id: int
129
137
  role: RoleSimpleSchema
130
138
  scope: str
@@ -139,12 +147,13 @@ class RoleGrantCreateSchema(Schema):
139
147
  """
140
148
  Schéma pour la création d'un role grant.
141
149
  """
150
+
142
151
  role: str
143
152
  scope: str
144
153
  actions: list[str]
145
154
  context: dict[str, Any] = {}
146
-
147
- @field_validator('actions')
155
+
156
+ @field_validator("actions")
148
157
  @classmethod
149
158
  def validate_actions(cls, v: list[str]) -> list[str]:
150
159
  """Valide que toutes les actions sont valides."""
@@ -155,10 +164,11 @@ class RoleGrantUpdateSchema(Schema):
155
164
  """
156
165
  Schéma pour la mise à jour d'un role grant.
157
166
  """
167
+
158
168
  actions: Optional[list[str]] = None
159
169
  context: Optional[dict[str, Any]] = None
160
-
161
- @field_validator('actions')
170
+
171
+ @field_validator("actions")
162
172
  @classmethod
163
173
  def validate_actions(cls, v: Optional[list[str]]) -> Optional[list[str]]:
164
174
  """Valide que toutes les actions sont valides."""
@@ -171,6 +181,7 @@ class GrantSchema(Schema):
171
181
  """
172
182
  Schéma pour un grant utilisateur.
173
183
  """
184
+
174
185
  id: int
175
186
  user_id: UUID
176
187
  role: RoleSimpleSchema
@@ -194,13 +205,14 @@ class GrantCreateSchema(Schema):
194
205
  """
195
206
  Schéma pour la création d'un grant utilisateur.
196
207
  """
208
+
197
209
  user_id: UUID
198
210
  scope: str
199
211
  actions: list[str]
200
212
  context: dict[str, Any] = {}
201
213
  role: str
202
-
203
- @field_validator('actions')
214
+
215
+ @field_validator("actions")
204
216
  @classmethod
205
217
  def validate_actions(cls, v: list[str]) -> list[str]:
206
218
  """Valide que toutes les actions sont valides."""
@@ -211,11 +223,12 @@ class GrantUpdateSchema(Schema):
211
223
  """
212
224
  Schéma pour la mise à jour d'un grant utilisateur.
213
225
  """
226
+
214
227
  actions: Optional[list[str]] = None
215
228
  context: Optional[dict[str, Any]] = None
216
229
  role: Optional[str] = None
217
-
218
- @field_validator('actions')
230
+
231
+ @field_validator("actions")
219
232
  @classmethod
220
233
  def validate_actions(cls, v: Optional[list[str]]) -> Optional[list[str]]:
221
234
  """Valide que toutes les actions sont valides."""
@@ -228,12 +241,13 @@ class PermissionCheckSchema(Schema):
228
241
  """
229
242
  Schéma pour une requête de vérification de permissions.
230
243
  """
244
+
231
245
  user_id: UUID
232
246
  scope: str
233
247
  required_actions: list[str]
234
248
  context: dict[str, Any] = {}
235
-
236
- @field_validator('required_actions')
249
+
250
+ @field_validator("required_actions")
237
251
  @classmethod
238
252
  def validate_actions(cls, v: list[str]) -> list[str]:
239
253
  """Valide que toutes les actions sont valides."""
@@ -244,6 +258,7 @@ class PermissionCheckResponseSchema(Schema):
244
258
  """
245
259
  Schéma pour la réponse d'une vérification de permissions.
246
260
  """
261
+
247
262
  allowed: bool
248
263
  user_id: UUID
249
264
  scope: str
@@ -254,16 +269,17 @@ class AssignRoleSchema(Schema):
254
269
  """
255
270
  Schéma pour assigner un rôle à un utilisateur.
256
271
  """
272
+
257
273
  user_id: UUID
258
274
  role: str
259
275
  scope: str
260
276
 
261
- @field_validator('scope')
277
+ @field_validator("scope")
262
278
  @classmethod
263
279
  def validate_scope(cls, v: str) -> str:
264
280
  """Valide que le scope est valide."""
265
- scopes = getattr(settings, 'ACCESS_SCOPES', [])
266
-
281
+ scopes = getattr(settings, "ACCESS_SCOPES", [])
282
+
267
283
  if v not in scopes:
268
284
  raise ValueError(f"Invalid scope '{v}'")
269
285
  return v
@@ -273,22 +289,23 @@ class OverrideGrantSchema(Schema):
273
289
  """
274
290
  Schéma pour modifier un grant utilisateur.
275
291
  """
292
+
276
293
  user_id: UUID
277
294
  scope: str
278
295
  role: str
279
296
  actions: list[str]
280
297
 
281
- @field_validator('scope')
298
+ @field_validator("scope")
282
299
  @classmethod
283
300
  def validate_scope(cls, v: str) -> str:
284
301
  """Valide que le scope est valide."""
285
- scopes = getattr(settings, 'ACCESS_SCOPES', [])
302
+ scopes = getattr(settings, "ACCESS_SCOPES", [])
286
303
 
287
304
  if v not in scopes:
288
305
  raise ValueError(f"Invalid scope '{v}'")
289
306
  return v
290
307
 
291
- @field_validator('actions')
308
+ @field_validator("actions")
292
309
  @classmethod
293
310
  def validate_actions(cls, v: list[str]) -> list[str]:
294
311
  """Valide que toutes les actions sont valides."""
@@ -299,15 +316,16 @@ class RevokeRoleSchema(Schema):
299
316
  """
300
317
  Schéma pour révoquer un rôle d'un utilisateur.
301
318
  """
319
+
302
320
  user_id: UUID
303
321
  scope: str
304
322
  role: str
305
323
 
306
- @field_validator('scope')
324
+ @field_validator("scope")
307
325
  @classmethod
308
326
  def validate_scope(cls, v: str) -> str:
309
327
  """Valide que le scope est valide."""
310
- scopes = getattr(settings, 'ACCESS_SCOPES', [])
328
+ scopes = getattr(settings, "ACCESS_SCOPES", [])
311
329
 
312
330
  if v not in scopes:
313
331
  raise ValueError(f"Invalid scope '{v}'")
@@ -318,6 +336,7 @@ class AssignGroupSchema(Schema):
318
336
  """
319
337
  Schéma pour assigner un groupe à un utilisateur.
320
338
  """
339
+
321
340
  user_id: UUID
322
341
  group: str
323
342
 
@@ -326,6 +345,7 @@ class RevokeGroupSchema(Schema):
326
345
  """
327
346
  Schéma pour révoquer un groupe d'un utilisateur.
328
347
  """
348
+
329
349
  user_id: UUID
330
350
  group: str
331
351
 
@@ -334,6 +354,7 @@ class GroupSyncResponseSchema(Schema):
334
354
  """
335
355
  Schéma pour la réponse de la synchronisation d'un groupe.
336
356
  """
357
+
337
358
  users_synced: int
338
359
  grants_updated: int
339
360
 
@@ -342,6 +363,7 @@ class PresetLoadResponseSchema(Schema):
342
363
  """
343
364
  Schéma pour la réponse du chargement d'un preset.
344
365
  """
366
+
345
367
  roles_created: int
346
368
  groups_created: int
347
369
  role_grants_created: int