oxutils 0.4.2__tar.gz → 0.4.4__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.2 → oxutils-0.4.4}/PKG-INFO +1 -1
  2. {oxutils-0.4.2 → oxutils-0.4.4}/pyproject.toml +1 -1
  3. oxutils-0.4.4/src/oxutils/__init__.py +53 -0
  4. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/celery/base.py +6 -1
  5. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/logger/settings.py +3 -1
  6. oxutils-0.4.4/src/oxutils/permissions/__init__.py +1 -0
  7. oxutils-0.4.4/src/oxutils/permissions/apps.py +23 -0
  8. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/checks.py +36 -0
  9. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/perms.py +58 -0
  10. oxutils-0.4.4/src/oxutils/permissions/presets.py +131 -0
  11. oxutils-0.4.2/src/oxutils/__init__.py +0 -28
  12. oxutils-0.4.2/src/oxutils/permissions/apps.py +0 -10
  13. oxutils-0.4.2/src/oxutils/users/migrations/__init__.py +0 -0
  14. {oxutils-0.4.2 → oxutils-0.4.4}/README.md +0 -0
  15. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/apps.py +0 -0
  16. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/__init__.py +0 -0
  17. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/apps.py +0 -0
  18. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/export.py +0 -0
  19. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/locale/fr/LC_MESSAGES/django.po +0 -0
  20. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/masks.py +0 -0
  21. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/migrations/0001_initial.py +0 -0
  22. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/migrations/__init__.py +0 -0
  23. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/models.py +0 -0
  24. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/settings.py +0 -0
  25. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/audit/utils.py +0 -0
  26. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/__init__.py +0 -0
  27. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/adapter.py +0 -0
  28. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/admin.py +0 -0
  29. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/app_settings.py +0 -0
  30. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/apps.py +0 -0
  31. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/constants.py +0 -0
  32. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/controllers.py +0 -0
  33. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/emails/__init__.py +0 -0
  34. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/emails/controllers.py +0 -0
  35. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/emails/schemas.py +0 -0
  36. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/emails/services.py +0 -0
  37. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/exceptions.py +0 -0
  38. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/__init__.py +0 -0
  39. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/backend.py +0 -0
  40. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/controllers.py +0 -0
  41. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/models.py +0 -0
  42. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/schemas.py +0 -0
  43. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/invitations/tokens.py +0 -0
  44. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/__init__.py +0 -0
  45. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/adapter.py +0 -0
  46. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/base/__init__.py +0 -0
  47. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/base/controllers.py +0 -0
  48. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/base/schemas.py +0 -0
  49. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/recovery_codes/__init__.py +0 -0
  50. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/recovery_codes/controllers.py +0 -0
  51. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/recovery_codes/flows.py +0 -0
  52. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/recovery_codes/schemas.py +0 -0
  53. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/recovery_codes/services.py +0 -0
  54. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/__ini__.py +0 -0
  55. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/controllers.py +0 -0
  56. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/flows.py +0 -0
  57. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/permissions.py +0 -0
  58. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/schemas.py +0 -0
  59. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/totp/services.py +0 -0
  60. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mfa/utils.py +0 -0
  61. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/migrations/0001_initial.py +0 -0
  62. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/migrations/__init__.py +0 -0
  63. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/mixins.py +0 -0
  64. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/models.py +0 -0
  65. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/password_reset/__init__.py +0 -0
  66. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/password_reset/controllers.py +0 -0
  67. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/password_reset/models.py +0 -0
  68. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/password_reset/permissions.py +0 -0
  69. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/password_reset/schemas.py +0 -0
  70. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/registration/__init__.py +0 -0
  71. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/registration/controllers.py +0 -0
  72. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/registration/schemas.py +0 -0
  73. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/schemas.py +0 -0
  74. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/sessions/__init__.py +0 -0
  75. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/sessions/controllers.py +0 -0
  76. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/sessions/schemas.py +0 -0
  77. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/signals.py +0 -0
  78. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/templatetags/__init__.py +0 -0
  79. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/templatetags/spa_urls.py +0 -0
  80. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/__init__.py +0 -0
  81. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/app_settings.py +0 -0
  82. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/models.py +0 -0
  83. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/schemas.py +0 -0
  84. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/tokens.py +0 -0
  85. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/tokens/utils.py +0 -0
  86. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/auth/utils.py +0 -0
  87. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/celery/__init__.py +0 -0
  88. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/celery/settings.py +0 -0
  89. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/conf.py +0 -0
  90. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/constants.py +0 -0
  91. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/context/__init__.py +0 -0
  92. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/context/site_name_processor.py +0 -0
  93. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/__init__.py +0 -0
  94. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/admin.py +0 -0
  95. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/apps.py +0 -0
  96. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/caches.py +0 -0
  97. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/controllers.py +0 -0
  98. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/enums.py +0 -0
  99. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/management/__init__.py +0 -0
  100. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/management/commands/__init__.py +0 -0
  101. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/management/commands/sync_currency.py +0 -0
  102. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/migrations/0001_initial.py +0 -0
  103. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/migrations/__init__.py +0 -0
  104. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/models.py +0 -0
  105. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/schemas.py +0 -0
  106. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/signals.py +0 -0
  107. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/tests.py +0 -0
  108. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/currency/utils.py +0 -0
  109. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/enums/__init__.py +0 -0
  110. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/enums/audit.py +0 -0
  111. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/enums/invoices.py +0 -0
  112. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/exceptions.py +0 -0
  113. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/functions.py +0 -0
  114. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/__init__.py +0 -0
  115. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/auth.py +0 -0
  116. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/middleware.py +0 -0
  117. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/models.py +0 -0
  118. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/tokens.py +0 -0
  119. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/jwt/utils.py +0 -0
  120. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/logger/__init__.py +0 -0
  121. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/logger/receivers.py +0 -0
  122. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/mixins/__init__.py +0 -0
  123. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/mixins/base.py +0 -0
  124. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/mixins/schemas.py +0 -0
  125. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/mixins/services.py +0 -0
  126. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/__init__.py +0 -0
  127. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/base.py +0 -0
  128. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/billing.py +0 -0
  129. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/change_tracker.py +0 -0
  130. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/fields.py +0 -0
  131. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/models/invoice.py +0 -0
  132. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/__init__.py +0 -0
  133. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/admin.py +0 -0
  134. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/apps.py +0 -0
  135. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/authorization.py +0 -0
  136. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/cacheops.py +0 -0
  137. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/caches.py +0 -0
  138. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/checks.py +0 -0
  139. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/constants.py +0 -0
  140. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/context.py +0 -0
  141. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/controllers.py +0 -0
  142. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/enums.py +0 -0
  143. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/exceptions.py +0 -0
  144. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/locale/fr/LC_MESSAGES/django.po +0 -0
  145. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/management/__init__.py +0 -0
  146. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/management/commands/__init__.py +0 -0
  147. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/management/commands/grant_tenant_owners.py +0 -0
  148. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/management/commands/init_oxiliere_system.py +0 -0
  149. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/middleware.py +0 -0
  150. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/migrations/__init__.py +0 -0
  151. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/models.py +0 -0
  152. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/permissions.py +0 -0
  153. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/schemas.py +0 -0
  154. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/services.py +0 -0
  155. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/settings.py +0 -0
  156. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/signals.py +0 -0
  157. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/tests.py +0 -0
  158. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/oxiliere/utils.py +0 -0
  159. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pagination/__init__.py +0 -0
  160. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pagination/cursor.py +0 -0
  161. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pdf/__init__.py +0 -0
  162. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pdf/printer.py +0 -0
  163. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pdf/utils.py +0 -0
  164. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/pdf/views.py +0 -0
  165. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/actions.py +0 -0
  166. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/admin.py +0 -0
  167. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/caches.py +0 -0
  168. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/constants.py +0 -0
  169. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/controllers.py +0 -0
  170. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/exceptions.py +0 -0
  171. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/locale/fr/LC_MESSAGES/django.po +0 -0
  172. {oxutils-0.4.2/src/oxutils/permissions → oxutils-0.4.4/src/oxutils/permissions/management}/__init__.py +0 -0
  173. {oxutils-0.4.2/src/oxutils/permissions/management → oxutils-0.4.4/src/oxutils/permissions/management/commands}/__init__.py +0 -0
  174. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/management/commands/load_permission_preset.py +0 -0
  175. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0001_initial.py +0 -0
  176. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0002_alter_grant_role.py +0 -0
  177. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +0 -0
  178. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0004_group_app_group_permissions_app_9a9924_idx.py +0 -0
  179. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0005_role_app.py +0 -0
  180. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0006_alter_rolegrant_options_and_more.py +0 -0
  181. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0007_grant_locked_alter_grant_role_and_more.py +0 -0
  182. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0008_remove_grant_unique_user_scope_role_and_more.py +0 -0
  183. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/migrations/0009_grant_is_active.py +0 -0
  184. {oxutils-0.4.2/src/oxutils/permissions/management/commands → oxutils-0.4.4/src/oxutils/permissions/migrations}/__init__.py +0 -0
  185. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/models.py +0 -0
  186. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/queryset.py +0 -0
  187. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/schemas.py +0 -0
  188. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/services.py +0 -0
  189. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/tests.py +0 -0
  190. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/permissions/utils.py +0 -0
  191. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/py.typed +0 -0
  192. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/s3.py +0 -0
  193. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/settings.py +0 -0
  194. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/account/email/base_message.txt +0 -0
  195. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/email/password/reset_email_message.html +0 -0
  196. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/email/password/reset_email_message.txt +0 -0
  197. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/email/password/reset_email_subject.txt +0 -0
  198. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/email/signup/email_message.html +0 -0
  199. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/email/signup/email_subject.txt +0 -0
  200. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/templates/verified.html +0 -0
  201. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/types.py +0 -0
  202. {oxutils-0.4.2/src/oxutils/permissions/migrations → oxutils-0.4.4/src/oxutils/users}/__init__.py +0 -0
  203. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/admin.py +0 -0
  204. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/apps.py +0 -0
  205. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/locale/fr/LC_MESSAGES/django.po +0 -0
  206. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/migrations/0001_initial.py +0 -0
  207. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +0 -0
  208. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/migrations/0003_user_photo.py +0 -0
  209. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/migrations/0004_alter_user_options.py +0 -0
  210. {oxutils-0.4.2/src/oxutils/users → oxutils-0.4.4/src/oxutils/users/migrations}/__init__.py +0 -0
  211. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/models.py +0 -0
  212. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/tests.py +0 -0
  213. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/users/utils.py +0 -0
  214. {oxutils-0.4.2 → oxutils-0.4.4}/src/oxutils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxutils
3
- Version: 0.4.2
3
+ Version: 0.4.4
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.2"
3
+ version = "0.4.4"
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"
@@ -0,0 +1,53 @@
1
+ """OxUtils — Production-ready Django utilities for multi-tenant SaaS.
2
+
3
+ Authentication & authorization:
4
+ - JWT authentication: Bearer, Cookie, and passive backends with JWKS support
5
+ - RBAC permissions: roles, groups, user grants with scope-based access
6
+ control (``ScopePermission``, ``ScopeAnyPermission``, etc.)
7
+ - Auto-discovery of permission presets from installed apps
8
+ - Complete auth system: registration, login/logout, password reset,
9
+ MFA, invitations, sessions — integrates with django-allauth
10
+ - Api exceptions with error codes and structured responses
11
+
12
+ Multi-tenancy:
13
+ - django-tenants integration with ``X-Organization-ID`` header routing
14
+ - Tenant / tenant-user models, schema-aware middleware and caching
15
+ - Tenant lifecycle signals, authorization, and system-tenant fallback
16
+
17
+ Infrastructure & tooling:
18
+ - Structured logging with correlation IDs, request metadata binding,
19
+ and pre-built ``LOGGING`` configuration (structlog)
20
+ - Audit log export to S3 with export-state tracking and status history
21
+ - Cursor-based pagination for Django Ninja APIs
22
+ - PDF generation via WeasyPrint (``Printer`` class and ``WeasyTemplateView``)
23
+ - Multi-currency support with rate syncing (BCC, Open Exchange Rates)
24
+ - Celery app with task auto-discovery and structlog integration
25
+ - S3 storage backend factory with env-var configuration
26
+
27
+ Model utilities:
28
+ - Reusable mixins: UUID PK, timestamps, user tracking, slug, ordering,
29
+ soft-delete with field masking (``SafeDeleteModelMixin``),
30
+ change tracking, invoicing, and billing
31
+ - Custom user model with email-based auth, ``oxi_id`` linking, and audit
32
+ - Custom Pydantic types (``EmailApiType``, etc.)
33
+
34
+ Other:
35
+ - HTTP header/cookie constants (oxi tokens, JWT tokens)
36
+ - Template context processor (site name & domain)
37
+ - Central pydantic-settings configuration (``oxi_settings``)
38
+ - Shared enums (invoice status, export status)
39
+ - Utility helpers: client IP detection, absolute URL building,
40
+ image validation, bound-request detection
41
+ """
42
+
43
+ __version__ = "0.4.4"
44
+
45
+ from oxutils.conf import AUDIT_MIDDLEWARE, UTILS_APPS
46
+ from oxutils.settings import oxi_settings
47
+
48
+ __all__ = [
49
+ "oxi_settings",
50
+ "UTILS_APPS",
51
+ "AUDIT_MIDDLEWARE",
52
+ "__version__",
53
+ ]
@@ -30,6 +30,9 @@ def receiver_setup_logging(loglevel, logfile, format, colorize, **kwargs): # pr
30
30
  "json_formatter": {
31
31
  "()": structlog.stdlib.ProcessorFormatter,
32
32
  "processor": structlog.processors.JSONRenderer(),
33
+ "foreign_pre_chain": [
34
+ structlog.processors.format_exc_info,
35
+ ],
33
36
  },
34
37
  "plain_console": {
35
38
  "()": structlog.stdlib.ProcessorFormatter,
@@ -40,6 +43,9 @@ def receiver_setup_logging(loglevel, logfile, format, colorize, **kwargs): # pr
40
43
  "processor": structlog.processors.KeyValueRenderer(
41
44
  key_order=['timestamp', 'level', 'event', 'logger']
42
45
  ),
46
+ "foreign_pre_chain": [
47
+ structlog.processors.format_exc_info,
48
+ ],
43
49
  },
44
50
  },
45
51
  "handlers": {
@@ -88,7 +94,6 @@ def receiver_setup_logging(loglevel, logfile, format, colorize, **kwargs): # pr
88
94
  structlog.stdlib.add_log_level,
89
95
  structlog.stdlib.PositionalArgumentsFormatter(),
90
96
  structlog.processors.StackInfoRenderer(),
91
- structlog.processors.format_exc_info,
92
97
  structlog.processors.UnicodeDecoder(),
93
98
  structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
94
99
  ],
@@ -16,6 +16,9 @@ LOGGING = {
16
16
  "json_formatter": {
17
17
  "()": structlog.stdlib.ProcessorFormatter,
18
18
  "processor": structlog.processors.JSONRenderer(),
19
+ "foreign_pre_chain": [
20
+ structlog.processors.format_exc_info,
21
+ ],
19
22
  },
20
23
  "plain_console": {
21
24
  "()": structlog.stdlib.ProcessorFormatter,
@@ -54,7 +57,6 @@ structlog.configure(
54
57
  structlog.stdlib.add_log_level,
55
58
  structlog.stdlib.PositionalArgumentsFormatter(),
56
59
  structlog.processors.StackInfoRenderer(),
57
- structlog.processors.format_exc_info,
58
60
  structlog.processors.UnicodeDecoder(),
59
61
  structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
60
62
  ],
@@ -0,0 +1,23 @@
1
+ from django.apps import AppConfig
2
+ from django.conf import settings
3
+
4
+
5
+ class PermissionsConfig(AppConfig):
6
+ default_auto_field = "django.db.models.BigAutoField"
7
+ name = "oxutils.permissions"
8
+
9
+ def ready(self):
10
+ """Import checks when app is ready."""
11
+ from . import checks # noqa
12
+
13
+ from .presets import (
14
+ register_preset,
15
+ register_access_scopes,
16
+ register_access_applications,
17
+ )
18
+
19
+ if hasattr(settings, "PERMISSION_PRESET"):
20
+ register_preset(settings.PERMISSION_PRESET)
21
+
22
+ register_access_applications()
23
+ register_access_scopes()
@@ -291,4 +291,40 @@ def check_permission_settings(app_configs, **kwargs):
291
291
  )
292
292
  )
293
293
 
294
+ # Validate EXTRA_PERMISSIONS
295
+ if hasattr(settings, 'EXTRA_PERMISSIONS'):
296
+ extra = settings.EXTRA_PERMISSIONS
297
+ if not isinstance(extra, (list, tuple)):
298
+ errors.append(
299
+ Error(
300
+ 'EXTRA_PERMISSIONS must be a list or tuple',
301
+ hint='Set EXTRA_PERMISSIONS = ["dotted.path.ToPermission", ...]',
302
+ id='permissions.E019',
303
+ )
304
+ )
305
+ else:
306
+ from django.utils.module_loading import import_string
307
+
308
+ for path in extra:
309
+ if not isinstance(path, str):
310
+ errors.append(
311
+ Error(
312
+ f'Each entry in EXTRA_PERMISSIONS must be a string, got {type(path).__name__}',
313
+ hint='Use dotted paths like "myapp.permissions.MyPermission"',
314
+ id='permissions.E020',
315
+ )
316
+ )
317
+ continue
318
+ try:
319
+ cls = import_string(path)
320
+ except ImportError:
321
+ errors.append(
322
+ Error(
323
+ f'Cannot import "{path}" from EXTRA_PERMISSIONS',
324
+ hint='Check that the module and class exist',
325
+ id='permissions.E021',
326
+ )
327
+ )
328
+ continue
329
+
294
330
  return errors
@@ -1,8 +1,10 @@
1
+ from functools import lru_cache
1
2
  from typing import Optional
2
3
 
3
4
  from django.conf import settings
4
5
  from django.core.exceptions import ImproperlyConfigured
5
6
  from django.http import HttpRequest
7
+ from django.utils.module_loading import import_string
6
8
  from ninja_extra.controllers import ControllerBase
7
9
  from ninja_extra.permissions import BasePermission
8
10
 
@@ -199,3 +201,59 @@ def access_manager(actions: str):
199
201
  )
200
202
 
201
203
  return ScopePermission(perm, context)
204
+
205
+
206
+ @lru_cache(maxsize=1)
207
+ def extra_permissions():
208
+ """
209
+ Return the list of permission instances defined in
210
+ ``EXTRA_PERMISSIONS`` (settings.py).
211
+
212
+ Each entry is a dotted path to an **already instantiated** permission
213
+ object (e.g. a module-level singleton). The object is imported via
214
+ :func:`django.utils.module_loading.import_string` and returned as-is.
215
+
216
+ The result is cached via :func:`functools.lru_cache` so that
217
+ ``import_string`` is only called once per process.
218
+
219
+ Example::
220
+
221
+ # myapp/permissions.py
222
+ from ninja_extra.permissions import BasePermission
223
+
224
+ class IsPremium(BasePermission):
225
+ def has_permission(self, request, controller):
226
+ return request.user.is_premium
227
+
228
+ IsPremium = IsPremium() # <-- singleton instance
229
+
230
+ # settings.py
231
+ EXTRA_PERMISSIONS = [
232
+ "myapp.permissions.IsPremium",
233
+ ]
234
+
235
+ # controller
236
+ from oxutils.permissions import extra_permissions
237
+
238
+ @api_controller(
239
+ "/api",
240
+ permissions=[*extra_permissions(), ScopePermission("articles:r")],
241
+ )
242
+ class MyController:
243
+ ...
244
+ """
245
+ paths = getattr(settings, "EXTRA_PERMISSIONS", [])
246
+ if not isinstance(paths, (list, tuple)):
247
+ raise ImproperlyConfigured(
248
+ "EXTRA_PERMISSIONS must be a list or tuple of dotted paths."
249
+ )
250
+ instances = []
251
+ for path in paths:
252
+ try:
253
+ instance = import_string(path)
254
+ except ImportError as exc:
255
+ raise ImproperlyConfigured(
256
+ f"Cannot import permission from EXTRA_PERMISSIONS: {path}"
257
+ ) from exc
258
+ instances.append(instance)
259
+ return instances
@@ -0,0 +1,131 @@
1
+ """
2
+ Permission preset auto-discovery.
3
+
4
+ Walk installed apps, collect their ``PERMISSION_PRESET`` dicts,
5
+ ``ACCESS_APPLICATION_NAME`` and ``ACCESS_SCOPES``, and merge them
6
+ into the global configuration.
7
+
8
+ Called from ``PermissionsConfig.ready()`` when the app registry is ready.
9
+ """
10
+
11
+ import importlib
12
+
13
+ import structlog
14
+ from django.apps import apps
15
+ from django.conf import settings
16
+
17
+ logger = structlog.get_logger(__name__)
18
+
19
+
20
+ def discover_app_presets() -> list[dict]:
21
+ """Walk installed apps and collect their ``PERMISSION_PRESET``."""
22
+ presets: list[dict] = []
23
+ for app_config in apps.get_app_configs():
24
+ try:
25
+ mod = importlib.import_module(f"{app_config.name}.permissions")
26
+ except (ModuleNotFoundError, ImportError):
27
+ continue
28
+
29
+ preset = getattr(mod, "PERMISSION_PRESET", None)
30
+ if not isinstance(preset, dict):
31
+ continue
32
+
33
+ for role in preset.get("roles", []):
34
+ role.setdefault("app", app_config.label)
35
+ for group in preset.get("groups", []):
36
+ group.setdefault("app", app_config.label)
37
+ for grant in preset.get("role_grants", []):
38
+ grant.setdefault("app", app_config.label)
39
+
40
+ presets.append(preset)
41
+ logger.info(
42
+ "permission_preset_discovered",
43
+ app=app_config.label,
44
+ roles=len(preset.get("roles", [])),
45
+ groups=len(preset.get("groups", [])),
46
+ grants=len(preset.get("role_grants", [])),
47
+ )
48
+
49
+ return presets
50
+
51
+
52
+ def discover_access_scopes() -> list[str]:
53
+ """Walk installed apps and collect their ``ACCESS_SCOPES``."""
54
+ scopes: list[str] = []
55
+ for app_config in apps.get_app_configs():
56
+ try:
57
+ mod = importlib.import_module(f"{app_config.name}.permissions")
58
+ except (ModuleNotFoundError, ImportError):
59
+ continue
60
+
61
+ app_scopes = getattr(mod, "ACCESS_SCOPES", None)
62
+ if isinstance(app_scopes, list):
63
+ for scope in app_scopes:
64
+ if scope not in scopes:
65
+ scopes.append(scope)
66
+ logger.info(
67
+ "access_scope_discovered",
68
+ app=app_config.label,
69
+ scope=scope,
70
+ )
71
+
72
+ return scopes
73
+
74
+
75
+ def discover_access_applications() -> list[str]:
76
+ """Walk installed apps and collect their ``ACCESS_APPLICATION_NAME``."""
77
+ applications: list[str] = []
78
+ for app_config in apps.get_app_configs():
79
+ try:
80
+ mod = importlib.import_module(f"{app_config.name}.permissions")
81
+ except (ModuleNotFoundError, ImportError):
82
+ continue
83
+
84
+ app_name = getattr(mod, "ACCESS_APPLICATION_NAME", None)
85
+ if isinstance(app_name, str) and app_name not in applications:
86
+ applications.append(app_name)
87
+ logger.info(
88
+ "access_application_discovered",
89
+ app=app_config.label,
90
+ application=app_name,
91
+ )
92
+
93
+ return applications
94
+
95
+
96
+ def register_preset(base_preset: dict) -> dict:
97
+ """Extend *base_preset* with presets discovered from installed apps."""
98
+ base_roles = base_preset.setdefault("roles", [])
99
+ base_groups = base_preset.setdefault("groups", [])
100
+ base_grants = base_preset.setdefault("role_grants", [])
101
+
102
+ for preset in discover_app_presets():
103
+ base_roles.extend(preset.get("roles", []))
104
+ base_groups.extend(preset.get("groups", []))
105
+ base_grants.extend(preset.get("role_grants", []))
106
+
107
+ return base_preset
108
+
109
+
110
+ def register_access_scopes() -> None:
111
+ """Extend ``settings.ACCESS_SCOPES`` with scopes discovered from installed apps."""
112
+ existing = list(getattr(settings, "ACCESS_SCOPES", []))
113
+
114
+ for scope in discover_access_scopes():
115
+ if scope not in existing:
116
+ existing.append(scope)
117
+
118
+ settings.ACCESS_SCOPES = existing
119
+ logger.info("access_scopes_registered", count=len(existing))
120
+
121
+
122
+ def register_access_applications() -> None:
123
+ """Extend ``settings.ACCESS_APPLICATIONS`` with apps discovered from installed apps."""
124
+ existing = list(getattr(settings, "ACCESS_APPLICATIONS", []))
125
+
126
+ for app_name in discover_access_applications():
127
+ if app_name not in existing:
128
+ existing.append(app_name)
129
+
130
+ settings.ACCESS_APPLICATIONS = existing
131
+ logger.info("access_applications_registered", count=len(existing))
@@ -1,28 +0,0 @@
1
- """OxUtils - Production-ready utilities for Django applications.
2
-
3
- This package provides:
4
- - JWT authentication with JWKS support
5
- - Multi-tenant architecture (django-tenants integration, middleware, signals)
6
- - Auth system: invitations, MFA, password reset, registration, sessions
7
- - Structured logging with correlation IDs
8
- - Audit system with S3 export
9
- - Celery integration
10
- - Django model mixins (ChangeTracker, CookieToken, SafeDelete)
11
- - Permission management & authorization
12
- - PDF generation
13
- - Pagination utilities
14
- - Currency utilities
15
- - Custom exceptions, enums, and type definitions
16
- """
17
-
18
- __version__ = "0.4.2"
19
-
20
- from oxutils.conf import AUDIT_MIDDLEWARE, UTILS_APPS
21
- from oxutils.settings import oxi_settings
22
-
23
- __all__ = [
24
- "oxi_settings",
25
- "UTILS_APPS",
26
- "AUDIT_MIDDLEWARE",
27
- "__version__",
28
- ]
@@ -1,10 +0,0 @@
1
- from django.apps import AppConfig
2
-
3
-
4
- class PermissionsConfig(AppConfig):
5
- default_auto_field = 'django.db.models.BigAutoField'
6
- name = 'oxutils.permissions'
7
-
8
- def ready(self):
9
- """Import checks when app is ready."""
10
- from . import checks # noqa
File without changes
File without changes
File without changes
File without changes