django-pfx 1.7.3.dev4__tar.gz → 1.7.3.dev6__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 (233) hide show
  1. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/.pre-commit-config.yaml +8 -8
  2. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/PKG-INFO +4 -1
  3. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/PKG-INFO +4 -1
  4. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/SOURCES.txt +24 -0
  5. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/requires.txt +4 -0
  6. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/conf.py +3 -1
  7. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/make_messages +1 -0
  8. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/__init__.py +0 -2
  9. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apps.py +15 -1
  10. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/default_settings.py +7 -0
  11. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/media_field.py +19 -1
  12. django_pfx-1.7.3.dev6/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  13. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +26 -12
  14. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/__init__.py +1 -0
  15. django_pfx-1.7.3.dev6/pfx/pfxcore/models/attachment_mixin.py +78 -0
  16. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/ordered_model_mixin.py +2 -1
  17. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/shortcuts.py +5 -0
  18. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/otp_code_email.txt +1 -1
  19. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/password_reset_email.txt +2 -2
  20. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/welcome_email.txt +1 -1
  21. django_pfx-1.7.3.dev6/pfx/settings/dev.py +34 -0
  22. django_pfx-1.7.3.dev6/pfx/userjobs/__init__.py +1 -0
  23. django_pfx-1.7.3.dev6/pfx/userjobs/apps.py +22 -0
  24. django_pfx-1.7.3.dev6/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
  25. django_pfx-1.7.3.dev6/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +154 -0
  26. django_pfx-1.7.3.dev6/pfx/userjobs/migrations/0001_initial.py +76 -0
  27. django_pfx-1.7.3.dev6/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +100 -0
  28. django_pfx-1.7.3.dev6/pfx/userjobs/models/__init__.py +2 -0
  29. django_pfx-1.7.3.dev6/pfx/userjobs/models/user_job.py +217 -0
  30. django_pfx-1.7.3.dev6/pfx/userjobs/models/user_job_attachment.py +32 -0
  31. django_pfx-1.7.3.dev6/pfx/userjobs/providers/__init__.py +4 -0
  32. django_pfx-1.7.3.dev6/pfx/userjobs/providers/user_job_django_q_executor.py +29 -0
  33. django_pfx-1.7.3.dev6/pfx/userjobs/providers/user_job_websocket_channel_provider.py +30 -0
  34. django_pfx-1.7.3.dev6/pfx/userjobs/tasks.py +93 -0
  35. django_pfx-1.7.3.dev6/pfx/userjobs/urls.py +14 -0
  36. django_pfx-1.7.3.dev6/pfx/userjobs/views/__init__.py +3 -0
  37. django_pfx-1.7.3.dev6/pfx/userjobs/views/user_job_attachment_view.py +17 -0
  38. django_pfx-1.7.3.dev6/pfx/userjobs/views/user_job_view.py +63 -0
  39. django_pfx-1.7.3.dev6/pfx/userjobs/views/user_websocket_consumer.py +65 -0
  40. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/requirements.txt +7 -1
  41. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/setup.cfg +1 -0
  42. django_pfx-1.7.3.dev6/tests/channel_group_send_calls.py +21 -0
  43. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/settings/common.py +28 -1
  44. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/__init__.py +3 -0
  45. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_auth_api.py +17 -14
  46. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_profiling_middleware.py +0 -1
  47. django_pfx-1.7.3.dev6/tests/tests/test_user_job_api.py +574 -0
  48. django_pfx-1.7.3.dev6/tests/tests/test_user_job_messages.py +128 -0
  49. django_pfx-1.7.3.dev6/tests/tests/test_user_job_model.py +302 -0
  50. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/urls.py +2 -1
  51. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/settings/common.py +26 -0
  52. django_pfx-1.7.3.dev6/tests_custom_user/settings/__init__.py +0 -0
  53. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/common.py +26 -0
  54. django_pfx-1.7.3.dev4/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  55. django_pfx-1.7.3.dev4/pfx/settings/dev.py +0 -8
  56. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/.gitignore +0 -0
  57. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/.gitlab-ci.yml +0 -0
  58. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/LICENSE +0 -0
  59. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/MANIFEST.in +0 -0
  60. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/README.md +0 -0
  61. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/dependency_links.txt +0 -0
  62. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/top_level.txt +0 -0
  63. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/Makefile +0 -0
  64. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/index.rst +0 -0
  65. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/api.views.rst +0 -0
  66. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/authentication.md +0 -0
  67. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/decorator.md +0 -0
  68. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/generate_openapi.md +0 -0
  69. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/getting_started.md +0 -0
  70. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/internationalisation.md +0 -0
  71. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/model.md +0 -0
  72. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/pfx_views.md +0 -0
  73. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/profiling.md +0 -0
  74. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/settings.md +0 -0
  75. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/doc/source/testing.md +0 -0
  76. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/img/pfx.png +0 -0
  77. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/img/pfx.svg +0 -0
  78. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/manage.py +0 -0
  79. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/__init__.py +0 -0
  80. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/__init__.py +0 -0
  81. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/parameters.py +0 -0
  82. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/schema.py +0 -0
  83. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/tags.py +0 -0
  84. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/decorator/__init__.py +0 -0
  85. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/decorator/rest.py +0 -0
  86. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/exceptions.py +0 -0
  87. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/__init__.py +0 -0
  88. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/decimal_field.py +0 -0
  89. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
  90. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/rich_text_field.py +0 -0
  91. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/http/__init__.py +0 -0
  92. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/http/json_response.py +0 -0
  93. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/__init__.py +0 -0
  94. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/__init__.py +0 -0
  95. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  96. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/profile.py +0 -0
  97. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/__init__.py +0 -0
  98. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/authentication.py +0 -0
  99. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/locale.py +0 -0
  100. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/profiling.py +0 -0
  101. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  102. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  103. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  104. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
  105. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/__init__.py +0 -0
  106. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
  107. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
  108. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
  109. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/cache_mixins.py +0 -0
  110. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/login_ban.py +0 -0
  111. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
  112. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/not_null_fields.py +0 -0
  113. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/pfx_models.py +0 -0
  114. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/pfx_user.py +0 -0
  115. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  116. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/serializers/__init__.py +0 -0
  117. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/serializers/json.py +0 -0
  118. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/settings.py +0 -0
  119. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/__init__.py +0 -0
  120. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/__init__.py +0 -0
  121. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/base.py +0 -0
  122. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/console.py +0 -0
  123. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/__init__.py +0 -0
  124. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/exceptions.py +0 -0
  125. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/local_storage.py +0 -0
  126. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/s3_storage.py +0 -0
  127. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  128. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  129. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  130. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/test.py +0 -0
  131. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/urls.py +0 -0
  132. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/__init__.py +0 -0
  133. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/authentication_views.py +0 -0
  134. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/fields.py +0 -0
  135. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/filters_views.py +0 -0
  136. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/locale_views.py +0 -0
  137. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
  138. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
  139. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  140. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  141. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/groups.py +0 -0
  142. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  143. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  144. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  145. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  146. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  147. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  148. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  149. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  150. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  151. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset.py +0 -0
  152. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  153. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  154. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  155. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  156. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  157. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/rest_views.py +0 -0
  158. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pfx/settings/__init__.py +0 -0
  159. {django_pfx-1.7.3.dev4/tests → django_pfx-1.7.3.dev6/pfx/userjobs/migrations}/__init__.py +0 -0
  160. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/pyproject.toml +0 -0
  161. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/serve-doc +0 -0
  162. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/setup.py +0 -0
  163. {django_pfx-1.7.3.dev4/tests/migrations → django_pfx-1.7.3.dev6/tests}/__init__.py +0 -0
  164. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/apps.py +0 -0
  165. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  166. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0001_initial.py +0 -0
  167. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0002_alter_book_cover.py +0 -0
  168. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0003_book_local_file.py +0 -0
  169. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0004_mfausermixin_fields.py +0 -0
  170. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0005_mfausermixin_fields_fix.py +0 -0
  171. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py +0 -0
  172. {django_pfx-1.7.3.dev4/tests/settings → django_pfx-1.7.3.dev6/tests/migrations}/__init__.py +0 -0
  173. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/models.py +0 -0
  174. {django_pfx-1.7.3.dev4/tests_base_user → django_pfx-1.7.3.dev6/tests/settings}/__init__.py +0 -0
  175. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/settings/ci.py +0 -0
  176. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/settings/dev.py +0 -0
  177. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/settings/dev_custom_example.py +0 -0
  178. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/settings/dev_default.py +0 -0
  179. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/basic_api_errors.py +0 -0
  180. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/basic_api_test.py +0 -0
  181. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_api_doc.py +0 -0
  182. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_api_doc_search.py +0 -0
  183. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_body_mixin.py +0 -0
  184. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_cache.py +0 -0
  185. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_client.py +0 -0
  186. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_choices.py +0 -0
  187. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_date.py +0 -0
  188. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_decimal.py +0 -0
  189. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_minutes_duration.py +0 -0
  190. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_one2many.py +0 -0
  191. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_rich_text.py +0 -0
  192. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_time.py +0 -0
  193. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_filters.py +0 -0
  194. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_locale_api.py +0 -0
  195. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
  196. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_perm_tests.py +0 -0
  197. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_permissions.py +0 -0
  198. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_perms_api.py +0 -0
  199. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_post_migrate_groups_update.py +0 -0
  200. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_settings.py +0 -0
  201. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_shortcuts.py +0 -0
  202. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_timezone_middleware.py +0 -0
  203. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_tools.py +0 -0
  204. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_user_queryset.py +0 -0
  205. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_view_decorators.py +0 -0
  206. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/tests/test_view_fields.py +0 -0
  207. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests/views.py +0 -0
  208. {django_pfx-1.7.3.dev4/tests_base_user/migrations → django_pfx-1.7.3.dev6/tests_base_user}/__init__.py +0 -0
  209. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/migrations/0001_initial.py +0 -0
  210. {django_pfx-1.7.3.dev4/tests_base_user/settings → django_pfx-1.7.3.dev6/tests_base_user/migrations}/__init__.py +0 -0
  211. {django_pfx-1.7.3.dev4/tests_custom_user → django_pfx-1.7.3.dev6/tests_base_user/settings}/__init__.py +0 -0
  212. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/settings/ci.py +0 -0
  213. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev.py +0 -0
  214. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev_custom_example.py +0 -0
  215. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev_default.py +0 -0
  216. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/tests/__init__.py +0 -0
  217. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/tests/test_api.py +0 -0
  218. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/tests/test_auth_api.py +0 -0
  219. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/urls.py +0 -0
  220. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_base_user/views.py +0 -0
  221. {django_pfx-1.7.3.dev4/tests_custom_user/migrations → django_pfx-1.7.3.dev6/tests_custom_user}/__init__.py +0 -0
  222. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/migrations/0001_initial.py +0 -0
  223. {django_pfx-1.7.3.dev4/tests_custom_user/settings → django_pfx-1.7.3.dev6/tests_custom_user/migrations}/__init__.py +0 -0
  224. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/models.py +0 -0
  225. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/ci.py +0 -0
  226. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev.py +0 -0
  227. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev_custom_example.py +0 -0
  228. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev_default.py +0 -0
  229. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/__init__.py +0 -0
  230. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/test_api.py +0 -0
  231. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/test_auth_api.py +0 -0
  232. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/urls.py +0 -0
  233. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev6}/tests_custom_user/views.py +0 -0
@@ -1,11 +1,11 @@
1
1
  repos:
2
- - repo: https://github.com/pre-commit/pre-commit-hooks
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
3
  rev: v4.3.0
4
4
  hooks:
5
- - id: check-yaml
6
- - id: end-of-file-fixer
7
- - id: trailing-whitespace
8
- - repo: local
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+ - repo: local
9
9
  hooks:
10
10
  - id: flake8
11
11
  name: flake8
@@ -13,17 +13,17 @@ repos:
13
13
  language: system
14
14
  types: [python]
15
15
  args: [--config=./setup.cfg]
16
- - repo: local
16
+ - repo: local
17
17
  hooks:
18
18
  - id: isort
19
19
  name: isort
20
20
  entry: isort
21
21
  language: system
22
22
  types: [python]
23
- - repo: local
23
+ - repo: local
24
24
  hooks:
25
25
  - id: make-messages
26
26
  name: make messages
27
27
  entry: ./make_messages
28
28
  language: system
29
- types: [python]
29
+ pass_filenames: false
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.3.dev4
3
+ Version: 1.7.3.dev6
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -37,6 +37,9 @@ Requires-Dist: dill
37
37
  Requires-Dist: nh3
38
38
  Provides-Extra: otp
39
39
  Requires-Dist: pyotp; extra == "otp"
40
+ Provides-Extra: heic-converter
41
+ Requires-Dist: python-magic; extra == "heic-converter"
42
+ Requires-Dist: pillow-heif; extra == "heic-converter"
40
43
  Dynamic: license-file
41
44
 
42
45
  # Django PFX
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.3.dev4
3
+ Version: 1.7.3.dev6
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -37,6 +37,9 @@ Requires-Dist: dill
37
37
  Requires-Dist: nh3
38
38
  Provides-Extra: otp
39
39
  Requires-Dist: pyotp; extra == "otp"
40
+ Provides-Extra: heic-converter
41
+ Requires-Dist: python-magic; extra == "heic-converter"
42
+ Requires-Dist: pillow-heif; extra == "heic-converter"
40
43
  Dynamic: license-file
41
44
 
42
45
  # Django PFX
@@ -73,6 +73,7 @@ pfx/pfxcore/migrations/operations/__init__.py
73
73
  pfx/pfxcore/migrations/operations/permissions.py
74
74
  pfx/pfxcore/models/__init__.py
75
75
  pfx/pfxcore/models/abstract_pfx_base_user.py
76
+ pfx/pfxcore/models/attachment_mixin.py
76
77
  pfx/pfxcore/models/cache_mixins.py
77
78
  pfx/pfxcore/models/login_ban.py
78
79
  pfx/pfxcore/models/mfa_user_mixin.py
@@ -125,8 +126,28 @@ pfx/pfxcore/views/parameters/subset_page_size.py
125
126
  pfx/pfxcore/views/parameters/subset_page_subset.py
126
127
  pfx/settings/__init__.py
127
128
  pfx/settings/dev.py
129
+ pfx/userjobs/__init__.py
130
+ pfx/userjobs/apps.py
131
+ pfx/userjobs/tasks.py
132
+ pfx/userjobs/urls.py
133
+ pfx/userjobs/locale/fr/LC_MESSAGES/django.mo
134
+ pfx/userjobs/locale/fr/LC_MESSAGES/django.po
135
+ pfx/userjobs/migrations/0001_initial.py
136
+ pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py
137
+ pfx/userjobs/migrations/__init__.py
138
+ pfx/userjobs/models/__init__.py
139
+ pfx/userjobs/models/user_job.py
140
+ pfx/userjobs/models/user_job_attachment.py
141
+ pfx/userjobs/providers/__init__.py
142
+ pfx/userjobs/providers/user_job_django_q_executor.py
143
+ pfx/userjobs/providers/user_job_websocket_channel_provider.py
144
+ pfx/userjobs/views/__init__.py
145
+ pfx/userjobs/views/user_job_attachment_view.py
146
+ pfx/userjobs/views/user_job_view.py
147
+ pfx/userjobs/views/user_websocket_consumer.py
128
148
  tests/__init__.py
129
149
  tests/apps.py
150
+ tests/channel_group_send_calls.py
130
151
  tests/models.py
131
152
  tests/urls.py
132
153
  tests/views.py
@@ -172,6 +193,9 @@ tests/tests/test_settings.py
172
193
  tests/tests/test_shortcuts.py
173
194
  tests/tests/test_timezone_middleware.py
174
195
  tests/tests/test_tools.py
196
+ tests/tests/test_user_job_api.py
197
+ tests/tests/test_user_job_messages.py
198
+ tests/tests/test_user_job_model.py
175
199
  tests/tests/test_user_queryset.py
176
200
  tests/tests/test_view_decorators.py
177
201
  tests/tests/test_view_fields.py
@@ -9,5 +9,9 @@ pytz
9
9
  dill
10
10
  nh3
11
11
 
12
+ [heic-converter]
13
+ python-magic
14
+ pillow-heif
15
+
12
16
  [otp]
13
17
  pyotp
@@ -25,7 +25,9 @@ settings.configure(
25
25
  'django.contrib.auth',
26
26
  'django.contrib.contenttypes',
27
27
  'django.contrib.postgres',
28
- 'pfx.pfxcore'])
28
+ 'pfx.pfxcore',
29
+ 'pfx.userjobs'],
30
+ STORAGE_DEFAULT='pfx.pfxcore.storage.LocalStorage')
29
31
  django.setup()
30
32
 
31
33
 
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env bash
2
2
  (cd pfx/pfxcore && django-admin makemessages -a)
3
+ (cd pfx/userjobs && django-admin makemessages -a)
3
4
  (cd tests && django-admin makemessages -a)
@@ -1,6 +1,4 @@
1
1
  from .apps import PfxAppConfig
2
2
  from .shortcuts import register_views
3
3
 
4
- default_app_config = 'pfx.pfxcore.apps.PfxCoreConfig'
5
-
6
4
  __PFX_VIEWS__ = []
@@ -1,5 +1,6 @@
1
1
  import inspect
2
2
  import logging
3
+ import os
3
4
  from pathlib import Path
4
5
 
5
6
  from django import apps
@@ -88,9 +89,22 @@ class PfxAppConfig(AppConfig):
88
89
 
89
90
  def ready(self):
90
91
  post_migrate.connect(update_groups_permissions_action, sender=self)
91
- return super().ready()
92
+ super().ready()
92
93
 
93
94
 
94
95
  class PfxCoreConfig(AppConfig):
95
96
  name = 'pfx.pfxcore'
96
97
  default = True
98
+
99
+ def ready(self):
100
+ if os.environ.get("RUN_MAIN") == "true":
101
+ try:
102
+ from pillow_heif import register_heif_opener
103
+ register_heif_opener()
104
+ logger.info("PFX HEIC opener registered.")
105
+ except Exception:
106
+ logger.warning(
107
+ "PFX HEIC opener not registered "
108
+ "(use `pip install django-pfx[heic-converter]` "
109
+ "to use it.)")
110
+ super().ready()
@@ -1,3 +1,5 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
1
3
  PFX_TOKEN_SHORT_VALIDITY = {'hours': 12}
2
4
  PFX_TOKEN_LONG_VALIDITY = {'days': 30}
3
5
  PFX_TOKEN_OTP_VALIDITY = {'minutes': 15}
@@ -42,3 +44,8 @@ PFX_MFA_BACKENDS = ["authenticator", "email"]
42
44
  PFX_MFA_FORCE = False
43
45
 
44
46
  PFX_SMS_BACKEND = 'pfx.pfxcore.sms.backends.console.ConsoleSMSBackend'
47
+
48
+ # PFX assume you have a log monitoring system (like Sentry), but
49
+ # you can adapt the message to your use case.
50
+ PFX_SYSTEM_ERROR_USER_MESSAGE = _(
51
+ "A system error occurred. Our support team has been notified.")
@@ -1,3 +1,4 @@
1
+ import io
1
2
  import logging
2
3
  from importlib import import_module
3
4
  from urllib.request import urlopen
@@ -42,7 +43,8 @@ def validate_media_json(value):
42
43
  class MediaField(models.JSONField):
43
44
  def __init__(
44
45
  self, *args, max_length=255, get_key=None, storage=None,
45
- auto_delete=False, extra_keys=None, **kwargs):
46
+ auto_delete=False, extra_keys=None,
47
+ convert_heic=False, **kwargs):
46
48
  self.get_key = get_key or self.get_default_key
47
49
  if not storage and not settings.STORAGE_DEFAULT:
48
50
  raise Exception(
@@ -51,6 +53,7 @@ class MediaField(models.JSONField):
51
53
  self.storage = storage or get_storage_class(settings.STORAGE_DEFAULT)
52
54
  self.auto_delete = auto_delete
53
55
  self.allowed_keys = DEFAULT_KEYS.union(extra_keys or set())
56
+ self.convert_heic = convert_heic
54
57
  self._db_value = None
55
58
 
56
59
  # Inject default validator if empty
@@ -107,9 +110,24 @@ class MediaField(models.JSONField):
107
110
  request, self.value_from_object(obj)['key'])
108
111
 
109
112
  def upload(self, obj, file, filename, **kwargs):
113
+ if self.convert_heic:
114
+ file, filename = self.convert_heic_file(file, filename)
110
115
  key = self.get_key(obj, filename)
111
116
  return self.to_python(self.storage.upload(key, file, **kwargs))
112
117
 
118
+ def convert_heic_file(self, file, filename):
119
+ import magic
120
+ from PIL import Image
121
+ mime_type = magic.from_buffer(file, mime=True)
122
+ if mime_type in ('image/heic', 'image/heif'):
123
+ img = Image.open(io.BytesIO(file))
124
+ buf = io.BytesIO()
125
+ img.convert("RGB").save(buf, format="PNG")
126
+
127
+ file = buf.getvalue()
128
+ filename = filename.rsplit(".", 1)[0] + '.png'
129
+ return file, filename
130
+
113
131
  def delete(self, value):
114
132
  return self.storage.delete(value)
115
133
 
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: \n"
9
9
  "Report-Msgid-Bugs-To: \n"
10
- "POT-Creation-Date: 2026-05-12 10:30+0200\n"
10
+ "POT-Creation-Date: 2026-05-21 16:23+0200\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -22,6 +22,12 @@ msgstr ""
22
22
  msgid "An internal server error occured."
23
23
  msgstr "Une erreur interne du serveur est survenue."
24
24
 
25
+ #: default_settings.py:51
26
+ msgid "A system error occurred. Our support team has been notified."
27
+ msgstr ""
28
+ "Une erreur système s’est produite. "
29
+ "Notre équipe d’assistance en a été informée."
30
+
25
31
  #: exceptions.py:53 exceptions.py:76
26
32
  #, python-brace-format
27
33
  msgid "{model} not found."
@@ -67,6 +73,10 @@ msgstr "utilisateur"
67
73
  msgid "users"
68
74
  msgstr "utilisateurs"
69
75
 
76
+ #: models/attachment_mixin.py:25
77
+ msgid "File"
78
+ msgstr "Fichier"
79
+
70
80
  #: models/login_ban.py:54
71
81
  msgid "Username"
72
82
  msgstr "Nom d’utilisateur"
@@ -139,10 +149,14 @@ msgstr "Configuration MFA requise"
139
149
  msgid "Is MFA forced"
140
150
  msgstr "MFA est forcé"
141
151
 
152
+ #: models/ordered_model_mixin.py:10
153
+ msgid "Sequence"
154
+ msgstr "Séquence"
155
+
142
156
  #: models/pfx_models.py:14
143
157
  #, python-format
144
158
  msgid "%(model_name)s with this %(field_labels)s already exists."
145
- msgstr "%(model_name)s avec ce/cette %(field_labels)s éxiste déjà."
159
+ msgstr "%(model_name)s avec ce/cette %(field_labels)s existe déjà."
146
160
 
147
161
  #: shortcuts.py:52
148
162
  #, python-brace-format
@@ -172,7 +186,7 @@ msgstr "{key} doit être « true », « false », « 1 », « 0 
172
186
  #: templates/registration/otp_code_email.txt:2
173
187
  #, python-format
174
188
  msgid ""
175
- "You're receiving this email because you requested an authentication code at "
189
+ "Youre receiving this email because you requested an authentication code at "
176
190
  "%(site_name)s."
177
191
  msgstr ""
178
192
  "Vous recevez cet e-mail parce que vous avez demandé un code d’authentication "
@@ -191,14 +205,14 @@ msgstr "Ce code est valable durant %(otp_validity)s minutes."
191
205
  #: templates/registration/password_reset_email.txt:10
192
206
  #: templates/registration/welcome_email.txt:10
193
207
  msgid "Thanks for using our site!"
194
- msgstr "Merci d'utiliser notre site !"
208
+ msgstr "Merci dutiliser notre site !"
195
209
 
196
210
  #: templates/registration/otp_code_email.txt:10
197
211
  #: templates/registration/password_reset_email.txt:12
198
212
  #: templates/registration/welcome_email.txt:12
199
213
  #, python-format
200
214
  msgid "The %(site_name)s team"
201
- msgstr "L'équipe de %(site_name)s"
215
+ msgstr "L’équipe de %(site_name)s"
202
216
 
203
217
  #: templates/registration/otp_code_subject.txt:2
204
218
  #, python-format
@@ -208,7 +222,7 @@ msgstr "Nouveau code d’authentication pour %(site_name)s"
208
222
  #: templates/registration/password_reset_email.txt:2
209
223
  #, python-format
210
224
  msgid ""
211
- "You're receiving this email because you requested a password reset for your "
225
+ "Youre receiving this email because you requested a password reset for your "
212
226
  "user account at %(site_name)s."
213
227
  msgstr ""
214
228
  "Vous recevez cet e-mail parce que vous avez demandé une réinitialisation du "
@@ -223,8 +237,8 @@ msgstr ""
223
237
 
224
238
  #: templates/registration/password_reset_email.txt:8
225
239
  #: templates/registration/welcome_email.txt:8
226
- msgid "Your username, in case you've forgotten:"
227
- msgstr "Votre nom d'utilisateur, au cas où vous l'auriez oublié :"
240
+ msgid "Your username, in case youve forgotten:"
241
+ msgstr "Votre nom dutilisateur, au cas où vous lauriez oublié :"
228
242
 
229
243
  #: templates/registration/password_reset_subject.txt:2
230
244
  #, python-format
@@ -281,11 +295,11 @@ msgstr "Un mot de passe vide n’est pas autorisé"
281
295
 
282
296
  #: views/authentication_views.py:557
283
297
  msgid "User and token are valid"
284
- msgstr "L'utilisateur et le token sont valides"
298
+ msgstr "Lutilisateur et le token sont valides"
285
299
 
286
300
  #: views/authentication_views.py:559
287
301
  msgid "User or token is invalid"
288
- msgstr "L'utilisateur ou le token est invalide"
302
+ msgstr "Lutilisateur ou le token est invalide"
289
303
 
290
304
  #: views/authentication_views.py:671
291
305
  msgid "OTP is already enabled"
@@ -314,7 +328,7 @@ msgstr ""
314
328
 
315
329
  #: views/authentication_views.py:1082
316
330
  msgid "A new authentication code has been sent by email."
317
- msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
331
+ msgstr "Un nouveau code dauthentification a été envoyé par e-mail."
318
332
 
319
333
  #: views/filters_views.py:81
320
334
  #, python-brace-format
@@ -333,7 +347,7 @@ msgstr "Le paramètre object est requis pour move={move}."
333
347
  #: views/ordered_rest_view_mixin.py:39
334
348
  #, python-brace-format
335
349
  msgid "object {pk} does not exists in this move context."
336
- msgstr "object {pk} n'existe pas dans ce contexte de déplacement."
350
+ msgstr "object {pk} nexiste pas dans ce contexte de déplacement."
337
351
 
338
352
  #: views/rest_views.py:228 views/rest_views.py:385
339
353
  #, python-brace-format
@@ -1,4 +1,5 @@
1
1
  from .abstract_pfx_base_user import AbstractPFXBaseUser, AbstractPFXUser
2
+ from .attachment_mixin import AttachmentMixin
2
3
  from .cache_mixins import CacheableMixin, CacheDependsMixin
3
4
  from .login_ban import LoginBan
4
5
  from .mfa_user_mixin import MFAUserMixin, OtpUserMixin
@@ -0,0 +1,78 @@
1
+ import logging
2
+
3
+ from django.conf import settings
4
+ from django.db import models
5
+ from django.utils.module_loading import import_string
6
+ from django.utils.translation import gettext_lazy as _
7
+
8
+ from pfx.pfxcore.fields import MediaField
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ file_field_overrides_error = (
13
+ "PFX_ATTACHMENT_FILE_FIELD_OVERRIDES must be:\n"
14
+ "- a dict.\n"
15
+ "- a callable returning a dict.\n"
16
+ "- a dotted import path to a callable returning a dict.\n")
17
+
18
+
19
+ def _get_file_key(obj, filename):
20
+ return obj.get_file_key(filename)
21
+
22
+
23
+ def _get_attachment_file_field_kwargs():
24
+ kwargs = dict(
25
+ verbose_name=_("File"), get_key=_get_file_key,
26
+ auto_delete=True, blank=True, null=True)
27
+
28
+ try:
29
+ func_path = getattr(
30
+ settings, 'PFX_ATTACHMENT_FILE_FIELD_OVERRIDES', None)
31
+ custom_kwargs = {}
32
+ if func_path:
33
+ if isinstance(func_path, dict):
34
+ custom_kwargs = func_path
35
+ elif callable(func_path):
36
+ custom_kwargs = func_path()
37
+ else:
38
+ custom_kwargs = import_string(func_path)()
39
+ if custom_kwargs:
40
+ kwargs.update(custom_kwargs)
41
+ except Exception as e:
42
+ raise TypeError(
43
+ "PFX_ATTACHMENT_FILE_FIELD_OVERRIDES must be:\n"
44
+ "- a dict.\n"
45
+ "- a callable returning a dict.\n"
46
+ "- a dotted import path to a callable returning a dict.\n"
47
+ ) from e
48
+
49
+ return kwargs
50
+
51
+
52
+ class AttachmentMixin(models.Model):
53
+ file = MediaField(**_get_attachment_file_field_kwargs())
54
+
55
+ class Meta:
56
+ abstract = True
57
+
58
+ def get_file_key(self, filename):
59
+ raise NotImplementedError()
60
+
61
+ def __str__(self):
62
+ return (self.file or {}).get('name', '')
63
+
64
+ @property
65
+ def url(self):
66
+ if not getattr(self, 'api', None):
67
+ raise RuntimeError(
68
+ f"api attribute is not defined on {self.__class__}")
69
+ return f'{self.api}/{self.pk}/file'
70
+
71
+ def json_repr(self, **values):
72
+ return super().json_repr(
73
+ file={
74
+ 'url': self.url,
75
+ 'name': (self.file or {}).get('name'),
76
+ 'content-type': (self.file or {}).get('content-type'),
77
+ 'content-length': (self.file or {}).get('content-length')},
78
+ **values)
@@ -1,12 +1,13 @@
1
1
  from django.db import models
2
2
  from django.db.models import F, Max, Min
3
+ from django.utils.translation import gettext_lazy as _
3
4
 
4
5
 
5
6
  class OrderedModelMixin(models.Model):
6
7
  ordered_by = []
7
8
  ordered_default = 'last'
8
9
 
9
- seq = models.PositiveBigIntegerField("Séquence")
10
+ seq = models.PositiveBigIntegerField(_("Sequence"))
10
11
 
11
12
  class Meta:
12
13
  abstract = True
@@ -167,3 +167,8 @@ def file_extension(filename):
167
167
  return ''.join(suffixes[-2:])
168
168
  else:
169
169
  return suffixes[-1]
170
+
171
+
172
+ def get_system_error_user_message(context=None):
173
+ # use str() to force lazy gettext string to be translated.
174
+ return str(settings.PFX_SYSTEM_ERROR_USER_MESSAGE)
@@ -1,5 +1,5 @@
1
1
  {% load i18n %}{% autoescape off %}
2
- {% blocktrans %}You're receiving this email because you requested an authentication code at {{ site_name }}.{% endblocktrans %}
2
+ {% blocktrans %}Youre receiving this email because you requested an authentication code at {{ site_name }}.{% endblocktrans %}
3
3
 
4
4
  {% trans "Authentication code:" %} {{ otp_code }}
5
5
 
@@ -1,11 +1,11 @@
1
1
  {% load i18n %}{% autoescape off %}
2
- {% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
2
+ {% blocktrans %}Youre receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
3
3
 
4
4
  {% trans "Please go to the following page and choose a new password:" %}
5
5
  {% block reset_link %}
6
6
  {{ reset_url }}
7
7
  {% endblock %}
8
- {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
8
+ {% trans "Your username, in case youve forgotten:" %} {{ user.get_username }}
9
9
 
10
10
  {% trans "Thanks for using our site!" %}
11
11
 
@@ -5,7 +5,7 @@
5
5
  {% block reset_link %}
6
6
  {{ reset_url }}
7
7
  {% endblock %}
8
- {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
8
+ {% trans "Your username, in case youve forgotten:" %} {{ user.get_username }}
9
9
 
10
10
  {% trans "Thanks for using our site!" %}
11
11
 
@@ -0,0 +1,34 @@
1
+ SECRET_KEY = 'fake-key'
2
+ INSTALLED_APPS = [
3
+ 'django.contrib.auth',
4
+ 'django.contrib.contenttypes',
5
+ 'django.contrib.postgres',
6
+ 'pfx.pfxcore',
7
+ 'pfx.userjobs',
8
+ ]
9
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
10
+ STORAGE_DEFAULT = 'pfx.pfxcore.storage.LocalStorage'
11
+
12
+ CACHE_MEMORY = {
13
+ 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
14
+ 'LOCATION': 'unique-snowflake',
15
+ }
16
+ CACHES = {
17
+ 'default': CACHE_MEMORY,
18
+ 'django-q': CACHE_MEMORY
19
+ }
20
+
21
+ CHANNEL_LAYERS = {
22
+ "default": {
23
+ "BACKEND": "channels.layers.InMemoryChannelLayer"
24
+ }
25
+ }
26
+
27
+ Q_CLUSTER = {
28
+ 'retry': 600,
29
+ 'timeout': 300,
30
+ 'sync': True,
31
+ 'catch_up': False,
32
+ 'max_attempts': 5,
33
+ 'orm': 'default'
34
+ }
@@ -0,0 +1 @@
1
+ from .apps import UserJobsConfig
@@ -0,0 +1,22 @@
1
+ from django.apps import AppConfig
2
+ from django.db.models.signals import post_migrate
3
+
4
+
5
+ def register_periodic_tasks(sender, **kwargs):
6
+ from . import tasks
7
+ tasks.register_periodic_tasks()
8
+
9
+
10
+ class UserJobsConfig(AppConfig):
11
+ name = 'pfx.userjobs'
12
+ default = True
13
+
14
+ def ready(self):
15
+ from pfx.userjobs.models.user_job import (
16
+ get_executor,
17
+ get_websocket_provider,
18
+ )
19
+ get_executor().validate_setup()
20
+ get_websocket_provider().validate_setup()
21
+ post_migrate.connect(register_periodic_tasks, sender=self)
22
+ super().ready()