django-pfx 1.7.4.dev2__tar.gz → 1.7.5.dev3__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 (307) hide show
  1. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/.gitlab-ci.yml +2 -0
  2. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/PKG-INFO +1 -1
  3. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/PKG-INFO +1 -1
  4. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/SOURCES.txt +19 -9
  5. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/scm_file_list.json +19 -9
  6. django_pfx-1.7.5.dev3/django_pfx.egg-info/scm_version.json +8 -0
  7. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/email_backend/q_mailjet_email_backend.py +2 -2
  8. django_pfx-1.7.5.dev3/pfx/emails/migrations/0004_alter_email_mail_from.py +21 -0
  9. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/models/email.py +3 -2
  10. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/shortcuts.py +10 -7
  11. django_pfx-1.7.5.dev3/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  12. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +16 -50
  13. django_pfx-1.7.5.dev3/pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py +22 -0
  14. django_pfx-1.7.5.dev3/pfx/pfxcore/migrations/0007_alter_pfxuser_options.py +18 -0
  15. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/abstract_pfx_base_user.py +36 -5
  16. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/pfx_models.py +12 -1
  17. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/shortcuts.py +10 -3
  18. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/test.py +2 -2
  19. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/authentication_views.py +22 -18
  20. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/views/user_websocket_consumer.py +6 -4
  21. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/locale/fr/LC_MESSAGES/django.po +3 -3
  22. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/migrations/0001_initial.py +21 -10
  23. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/models.py +2 -15
  24. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_auth_api.py +167 -30
  25. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_emails_send_email_message.py +25 -6
  26. django_pfx-1.7.5.dev3/tests_base_user/tests/test_api.py +74 -0
  27. django_pfx-1.7.5.dev3/tests_base_user/tests/test_auth_api.py +180 -0
  28. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/views.py +1 -1
  29. django_pfx-1.7.5.dev3/tests_custom_user/migrations/0001_initial.py +41 -0
  30. django_pfx-1.7.5.dev3/tests_custom_user/models.py +55 -0
  31. django_pfx-1.7.5.dev3/tests_custom_user/tests/test_api.py +78 -0
  32. django_pfx-1.7.5.dev3/tests_custom_user/tests/test_auth_api.py +195 -0
  33. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/views.py +1 -1
  34. django_pfx-1.7.5.dev3/tests_user_email_login/__init__.py +0 -0
  35. {django_pfx-1.7.4.dev2/tests_custom_user → django_pfx-1.7.5.dev3/tests_user_email_login}/migrations/0001_initial.py +8 -2
  36. django_pfx-1.7.5.dev3/tests_user_email_login/migrations/__init__.py +0 -0
  37. django_pfx-1.7.5.dev3/tests_user_email_login/models.py +44 -0
  38. django_pfx-1.7.5.dev3/tests_user_email_login/settings/__init__.py +0 -0
  39. django_pfx-1.7.5.dev3/tests_user_email_login/settings/ci.py +18 -0
  40. django_pfx-1.7.5.dev3/tests_user_email_login/settings/common.py +106 -0
  41. django_pfx-1.7.5.dev3/tests_user_email_login/settings/dev.py +13 -0
  42. django_pfx-1.7.5.dev3/tests_user_email_login/settings/dev_custom_example.py +28 -0
  43. django_pfx-1.7.5.dev3/tests_user_email_login/settings/dev_default.py +12 -0
  44. django_pfx-1.7.5.dev3/tests_user_email_login/tests/__init__.py +2 -0
  45. django_pfx-1.7.5.dev3/tests_user_email_login/tests/test_api.py +56 -0
  46. django_pfx-1.7.5.dev3/tests_user_email_login/tests/test_auth_api.py +195 -0
  47. django_pfx-1.7.5.dev3/tests_user_email_login/urls.py +13 -0
  48. django_pfx-1.7.5.dev3/tests_user_email_login/views.py +13 -0
  49. django_pfx-1.7.4.dev2/django_pfx.egg-info/scm_version.json +0 -8
  50. django_pfx-1.7.4.dev2/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  51. django_pfx-1.7.4.dev2/tests/migrations/0002_alter_book_cover.py +0 -21
  52. django_pfx-1.7.4.dev2/tests/migrations/0003_book_local_file.py +0 -21
  53. django_pfx-1.7.4.dev2/tests/migrations/0004_mfausermixin_fields.py +0 -43
  54. django_pfx-1.7.4.dev2/tests/migrations/0005_mfausermixin_fields_fix.py +0 -17
  55. django_pfx-1.7.4.dev2/tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py +0 -29
  56. django_pfx-1.7.4.dev2/tests/migrations/0007_attachment.py +0 -27
  57. django_pfx-1.7.4.dev2/tests/migrations/0008_remove_user_hotp_count_remove_user_hotp_expiry_and_more.py +0 -55
  58. django_pfx-1.7.4.dev2/tests_base_user/migrations/0001_initial.py +0 -13
  59. django_pfx-1.7.4.dev2/tests_base_user/tests/test_api.py +0 -32
  60. django_pfx-1.7.4.dev2/tests_base_user/tests/test_auth_api.py +0 -59
  61. django_pfx-1.7.4.dev2/tests_custom_user/models.py +0 -18
  62. django_pfx-1.7.4.dev2/tests_custom_user/tests/test_api.py +0 -24
  63. django_pfx-1.7.4.dev2/tests_custom_user/tests/test_auth_api.py +0 -57
  64. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/.gitignore +0 -0
  65. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/.pre-commit-config.yaml +0 -0
  66. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/LICENSE +0 -0
  67. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/MANIFEST.in +0 -0
  68. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/README.md +0 -0
  69. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/dependency_links.txt +0 -0
  70. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/requires.txt +0 -0
  71. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/django_pfx.egg-info/top_level.txt +0 -0
  72. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/Makefile +0 -0
  73. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/conf.py +0 -0
  74. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/index.rst +0 -0
  75. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/api.views.rst +0 -0
  76. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/authentication.md +0 -0
  77. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/decorator.md +0 -0
  78. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/generate_openapi.md +0 -0
  79. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/getting_started.md +0 -0
  80. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/internationalisation.md +0 -0
  81. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/model.md +0 -0
  82. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/pfx_views.md +0 -0
  83. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/profiling.md +0 -0
  84. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/settings.md +0 -0
  85. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/doc/source/testing.md +0 -0
  86. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/img/pfx.png +0 -0
  87. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/img/pfx.svg +0 -0
  88. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/make_messages +0 -0
  89. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/manage.py +0 -0
  90. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/__init__.py +0 -0
  91. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/__init__.py +0 -0
  92. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/apps.py +0 -0
  93. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/email_backend/__init__.py +0 -0
  94. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/exceptions.py +0 -0
  95. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/mailjet/__init__.py +0 -0
  96. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/mailjet/mailjet.py +0 -0
  97. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/mailjet/message_result.py +0 -0
  98. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/migrations/0001_initial.py +0 -0
  99. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/migrations/0002_alter_email_headers.py +0 -0
  100. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/migrations/0003_alter_email_options.py +0 -0
  101. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/migrations/__init__.py +0 -0
  102. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/models/__init__.py +0 -0
  103. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/providers/__init__.py +0 -0
  104. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/providers/email_django_q_executor.py +0 -0
  105. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/tasks.py +0 -0
  106. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/templates/emails/base_template.html +0 -0
  107. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/templates/emails/base_template.txt +0 -0
  108. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/templates/emails/base_template_subject.txt +0 -0
  109. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/urls.py +0 -0
  110. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/views/__init__.py +0 -0
  111. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/emails/views/email_rest_view.py +0 -0
  112. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/__init__.py +0 -0
  113. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/apidoc/__init__.py +0 -0
  114. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/apidoc/parameters.py +0 -0
  115. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/apidoc/schema.py +0 -0
  116. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/apidoc/tags.py +0 -0
  117. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/apps.py +0 -0
  118. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/decorator/__init__.py +0 -0
  119. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/decorator/rest.py +0 -0
  120. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/default_settings.py +0 -0
  121. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/exceptions.py +0 -0
  122. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/fields/__init__.py +0 -0
  123. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/fields/decimal_field.py +0 -0
  124. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/fields/media_field.py +0 -0
  125. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
  126. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/fields/rich_text_field.py +0 -0
  127. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/http/__init__.py +0 -0
  128. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/http/json_response.py +0 -0
  129. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/management/__init__.py +0 -0
  130. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/management/commands/__init__.py +0 -0
  131. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  132. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/management/commands/profile.py +0 -0
  133. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/__init__.py +0 -0
  134. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/authenticator.py +0 -0
  135. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/base.py +0 -0
  136. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/email.py +0 -0
  137. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/legacy.py +0 -0
  138. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/mfa/sms.py +0 -0
  139. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/__init__.py +0 -0
  140. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/authentication.py +0 -0
  141. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/locale.py +0 -0
  142. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/profiling.py +0 -0
  143. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/request_too_big_middleware.py +0 -0
  144. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/middleware/ws_cookie_authentication_middleware.py +0 -0
  145. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  146. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  147. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  148. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
  149. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py +0 -0
  150. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/__init__.py +0 -0
  151. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
  152. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
  153. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/__init__.py +0 -0
  154. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/attachment_mixin.py +0 -0
  155. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/cache_mixins.py +0 -0
  156. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/login_ban.py +0 -0
  157. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/mfa_device.py +0 -0
  158. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
  159. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/not_null_fields.py +0 -0
  160. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/ordered_model_mixin.py +0 -0
  161. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/pfx_user.py +0 -0
  162. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  163. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/serializers/__init__.py +0 -0
  164. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/serializers/json.py +0 -0
  165. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/settings.py +0 -0
  166. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/sms/__init__.py +0 -0
  167. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/sms/backends/__init__.py +0 -0
  168. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/sms/backends/base.py +0 -0
  169. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/sms/backends/console.py +0 -0
  170. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/storage/__init__.py +0 -0
  171. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/storage/exceptions.py +0 -0
  172. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/storage/local_storage.py +0 -0
  173. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/storage/s3_storage.py +0 -0
  174. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  175. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  176. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  177. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  178. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  179. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  180. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/urls.py +0 -0
  181. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/__init__.py +0 -0
  182. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/fields.py +0 -0
  183. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/filters_views.py +0 -0
  184. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/locale_views.py +0 -0
  185. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
  186. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/mfa_authentication_views.py +0 -0
  187. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
  188. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  189. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  190. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/groups.py +0 -0
  191. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  192. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  193. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  194. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  195. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  196. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  197. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  198. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  199. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  200. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset.py +0 -0
  201. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  202. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  203. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  204. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  205. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  206. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/pfxcore/views/rest_views.py +0 -0
  207. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/settings/__init__.py +0 -0
  208. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/settings/dev.py +0 -0
  209. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/__init__.py +0 -0
  210. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/apps.py +0 -0
  211. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
  212. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +0 -0
  213. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/migrations/0001_initial.py +0 -0
  214. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +0 -0
  215. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/migrations/0003_clean_scheduled_tasks.py +0 -0
  216. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/migrations/0004_userjob_summary_url.py +0 -0
  217. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/migrations/__init__.py +0 -0
  218. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/models/__init__.py +0 -0
  219. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/models/user_job.py +0 -0
  220. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/models/user_job_attachment.py +0 -0
  221. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/providers/__init__.py +0 -0
  222. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/providers/user_job_django_q_executor.py +0 -0
  223. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/providers/user_job_websocket_channel_provider.py +0 -0
  224. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/tasks.py +0 -0
  225. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/urls.py +0 -0
  226. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/views/__init__.py +0 -0
  227. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/views/user_job_attachment_view.py +0 -0
  228. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pfx/userjobs/views/user_job_view.py +0 -0
  229. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/pyproject.toml +0 -0
  230. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/requirements.txt +0 -0
  231. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/serve-doc +0 -0
  232. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/setup.cfg +0 -0
  233. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/setup.py +0 -0
  234. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/__init__.py +0 -0
  235. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/apps.py +0 -0
  236. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/channel_group_send_calls.py +0 -0
  237. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/mfa_urls.py +0 -0
  238. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/migrations/__init__.py +0 -0
  239. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/__init__.py +0 -0
  240. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/ci.py +0 -0
  241. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/common.py +0 -0
  242. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/dev.py +0 -0
  243. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/dev_custom_example.py +0 -0
  244. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/settings/dev_default.py +0 -0
  245. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/__init__.py +0 -0
  246. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/basic_api_errors.py +0 -0
  247. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/basic_api_test.py +0 -0
  248. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/mfa_test_utils.py +0 -0
  249. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_api_doc.py +0 -0
  250. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_api_doc_search.py +0 -0
  251. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_body_mixin.py +0 -0
  252. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_cache.py +0 -0
  253. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_client.py +0 -0
  254. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_emails_email_api.py +0 -0
  255. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_emails_email_model.py +0 -0
  256. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_emails_q_mailjet_email_backend.py +0 -0
  257. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_choices.py +0 -0
  258. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_date.py +0 -0
  259. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_decimal.py +0 -0
  260. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_minutes_duration.py +0 -0
  261. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_one2many.py +0 -0
  262. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_rich_text.py +0 -0
  263. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_fields_time.py +0 -0
  264. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_filters.py +0 -0
  265. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_locale_api.py +0 -0
  266. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_mfa_legacy.py +0 -0
  267. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_mfa_login_api.py +0 -0
  268. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_mfa_setup_api.py +0 -0
  269. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
  270. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_perm_tests.py +0 -0
  271. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_permissions.py +0 -0
  272. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_perms_api.py +0 -0
  273. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_post_migrate_groups_update.py +0 -0
  274. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_profiling_middleware.py +0 -0
  275. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_settings.py +0 -0
  276. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_shortcuts.py +0 -0
  277. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_timezone_middleware.py +0 -0
  278. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_tools.py +0 -0
  279. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_user_job_api.py +0 -0
  280. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_user_job_messages.py +0 -0
  281. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_user_job_model.py +0 -0
  282. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_user_queryset.py +0 -0
  283. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_user_websocket.py +0 -0
  284. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_view_decorators.py +0 -0
  285. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/tests/test_view_fields.py +0 -0
  286. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/urls.py +0 -0
  287. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests/views.py +0 -0
  288. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/__init__.py +0 -0
  289. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/migrations/__init__.py +0 -0
  290. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/__init__.py +0 -0
  291. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/ci.py +0 -0
  292. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/common.py +0 -0
  293. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/dev.py +0 -0
  294. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/dev_custom_example.py +0 -0
  295. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/settings/dev_default.py +0 -0
  296. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/tests/__init__.py +0 -0
  297. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_base_user/urls.py +0 -0
  298. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/__init__.py +0 -0
  299. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/migrations/__init__.py +0 -0
  300. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/__init__.py +0 -0
  301. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/ci.py +0 -0
  302. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/common.py +0 -0
  303. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/dev.py +0 -0
  304. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/dev_custom_example.py +0 -0
  305. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/settings/dev_default.py +0 -0
  306. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/tests/__init__.py +0 -0
  307. {django_pfx-1.7.4.dev2 → django_pfx-1.7.5.dev3}/tests_custom_user/urls.py +0 -0
@@ -38,6 +38,7 @@ quality check:
38
38
  - python manage.py makemigrations --check --dry-run
39
39
  - python manage.py makemigrations tests_base_user --check --dry-run
40
40
  - python manage.py makemigrations tests_custom_user --check --dry-run
41
+ - python manage.py makemigrations tests_user_email_login --check --dry-run
41
42
 
42
43
  test:
43
44
  image: $IMAGE
@@ -52,6 +53,7 @@ test:
52
53
  - coverage run -a --source='.' manage.py test
53
54
  - coverage run -a --source='.' manage.py test tests_base_user
54
55
  - coverage run -a --source='.' manage.py test tests_custom_user
56
+ - coverage run -a --source='.' manage.py test tests_user_email_login
55
57
  - coverage report
56
58
  - coverage xml
57
59
  - coverage html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.4.dev2
3
+ Version: 1.7.5.dev3
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.4.dev2
3
+ Version: 1.7.5.dev3
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
@@ -49,6 +49,7 @@ pfx/emails/mailjet/message_result.py
49
49
  pfx/emails/migrations/0001_initial.py
50
50
  pfx/emails/migrations/0002_alter_email_headers.py
51
51
  pfx/emails/migrations/0003_alter_email_options.py
52
+ pfx/emails/migrations/0004_alter_email_mail_from.py
52
53
  pfx/emails/migrations/__init__.py
53
54
  pfx/emails/models/__init__.py
54
55
  pfx/emails/models/email.py
@@ -103,6 +104,8 @@ pfx/pfxcore/migrations/0002_pfxpermissionsuser.py
103
104
  pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py
104
105
  pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py
105
106
  pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py
107
+ pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py
108
+ pfx/pfxcore/migrations/0007_alter_pfxuser_options.py
106
109
  pfx/pfxcore/migrations/__init__.py
107
110
  pfx/pfxcore/migrations/operations/__init__.py
108
111
  pfx/pfxcore/migrations/operations/permissions.py
@@ -193,13 +196,6 @@ tests/urls.py
193
196
  tests/views.py
194
197
  tests/locale/fr/LC_MESSAGES/django.po
195
198
  tests/migrations/0001_initial.py
196
- tests/migrations/0002_alter_book_cover.py
197
- tests/migrations/0003_book_local_file.py
198
- tests/migrations/0004_mfausermixin_fields.py
199
- tests/migrations/0005_mfausermixin_fields_fix.py
200
- tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py
201
- tests/migrations/0007_attachment.py
202
- tests/migrations/0008_remove_user_hotp_count_remove_user_hotp_expiry_and_more.py
203
199
  tests/migrations/__init__.py
204
200
  tests/settings/__init__.py
205
201
  tests/settings/ci.py
@@ -253,7 +249,6 @@ tests/tests/test_view_fields.py
253
249
  tests_base_user/__init__.py
254
250
  tests_base_user/urls.py
255
251
  tests_base_user/views.py
256
- tests_base_user/migrations/0001_initial.py
257
252
  tests_base_user/migrations/__init__.py
258
253
  tests_base_user/settings/__init__.py
259
254
  tests_base_user/settings/ci.py
@@ -278,4 +273,19 @@ tests_custom_user/settings/dev_custom_example.py
278
273
  tests_custom_user/settings/dev_default.py
279
274
  tests_custom_user/tests/__init__.py
280
275
  tests_custom_user/tests/test_api.py
281
- tests_custom_user/tests/test_auth_api.py
276
+ tests_custom_user/tests/test_auth_api.py
277
+ tests_user_email_login/__init__.py
278
+ tests_user_email_login/models.py
279
+ tests_user_email_login/urls.py
280
+ tests_user_email_login/views.py
281
+ tests_user_email_login/migrations/0001_initial.py
282
+ tests_user_email_login/migrations/__init__.py
283
+ tests_user_email_login/settings/__init__.py
284
+ tests_user_email_login/settings/ci.py
285
+ tests_user_email_login/settings/common.py
286
+ tests_user_email_login/settings/dev.py
287
+ tests_user_email_login/settings/dev_custom_example.py
288
+ tests_user_email_login/settings/dev_default.py
289
+ tests_user_email_login/tests/__init__.py
290
+ tests_user_email_login/tests/test_api.py
291
+ tests_user_email_login/tests/test_auth_api.py
@@ -69,15 +69,8 @@
69
69
  "tests/settings/__init__.py",
70
70
  "tests/settings/dev_custom_example.py",
71
71
  "tests/settings/ci.py",
72
- "tests/migrations/0004_mfausermixin_fields.py",
73
- "tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py",
74
- "tests/migrations/0008_remove_user_hotp_count_remove_user_hotp_expiry_and_more.py",
75
72
  "tests/migrations/__init__.py",
76
- "tests/migrations/0002_alter_book_cover.py",
77
73
  "tests/migrations/0001_initial.py",
78
- "tests/migrations/0007_attachment.py",
79
- "tests/migrations/0005_mfausermixin_fields_fix.py",
80
- "tests/migrations/0003_book_local_file.py",
81
74
  "tests/locale/fr/LC_MESSAGES/django.po",
82
75
  "doc/conf.py",
83
76
  "doc/index.rst",
@@ -167,6 +160,8 @@
167
160
  "pfx/pfxcore/templates/registration/otp_code_email.txt",
168
161
  "pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py",
169
162
  "pfx/pfxcore/migrations/__init__.py",
163
+ "pfx/pfxcore/migrations/0007_alter_pfxuser_options.py",
164
+ "pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py",
170
165
  "pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py",
171
166
  "pfx/pfxcore/migrations/0001_initial.py",
172
167
  "pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py",
@@ -239,6 +234,7 @@
239
234
  "pfx/emails/migrations/0002_alter_email_headers.py",
240
235
  "pfx/emails/migrations/__init__.py",
241
236
  "pfx/emails/migrations/0001_initial.py",
237
+ "pfx/emails/migrations/0004_alter_email_mail_from.py",
242
238
  "pfx/emails/providers/email_django_q_executor.py",
243
239
  "pfx/emails/providers/__init__.py",
244
240
  "pfx/emails/email_backend/q_mailjet_email_backend.py",
@@ -258,6 +254,21 @@
258
254
  "tests_custom_user/settings/ci.py",
259
255
  "tests_custom_user/migrations/__init__.py",
260
256
  "tests_custom_user/migrations/0001_initial.py",
257
+ "tests_user_email_login/urls.py",
258
+ "tests_user_email_login/views.py",
259
+ "tests_user_email_login/__init__.py",
260
+ "tests_user_email_login/models.py",
261
+ "tests_user_email_login/tests/test_api.py",
262
+ "tests_user_email_login/tests/test_auth_api.py",
263
+ "tests_user_email_login/tests/__init__.py",
264
+ "tests_user_email_login/settings/dev.py",
265
+ "tests_user_email_login/settings/common.py",
266
+ "tests_user_email_login/settings/dev_default.py",
267
+ "tests_user_email_login/settings/__init__.py",
268
+ "tests_user_email_login/settings/dev_custom_example.py",
269
+ "tests_user_email_login/settings/ci.py",
270
+ "tests_user_email_login/migrations/__init__.py",
271
+ "tests_user_email_login/migrations/0001_initial.py",
261
272
  "tests_base_user/urls.py",
262
273
  "tests_base_user/views.py",
263
274
  "tests_base_user/__init__.py",
@@ -270,7 +281,6 @@
270
281
  "tests_base_user/settings/__init__.py",
271
282
  "tests_base_user/settings/dev_custom_example.py",
272
283
  "tests_base_user/settings/ci.py",
273
- "tests_base_user/migrations/__init__.py",
274
- "tests_base_user/migrations/0001_initial.py"
284
+ "tests_base_user/migrations/__init__.py"
275
285
  ]
276
286
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.7.4",
3
+ "distance": 3,
4
+ "node": "ga9e75757076cdd1b35fb703f8ef59937d9689ba0",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-30"
8
+ }
@@ -7,7 +7,7 @@ from django.core.mail import EmailMultiAlternatives
7
7
  from django.core.mail.backends.base import BaseEmailBackend
8
8
 
9
9
  from pfx.emails.models import get_email_model
10
- from pfx.emails.shortcuts import default_mail_from, default_reply_to
10
+ from pfx.emails.shortcuts import default_mail_from_json, default_reply_to
11
11
 
12
12
 
13
13
  def getaddresses(fieldvalues):
@@ -28,7 +28,7 @@ class QMailjetEmailBackend(BaseEmailBackend):
28
28
 
29
29
  def create_mail(self, message):
30
30
  if not message.from_email:
31
- mail_from = default_mail_from()
31
+ mail_from = default_mail_from_json()
32
32
  else:
33
33
  mail_from = self.mail_dict(*getaddresses(
34
34
  [message.from_email])[0])
@@ -0,0 +1,21 @@
1
+ # Generated by Django 4.2.30 on 2026-07-30 01:07
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations, models
5
+
6
+ import pfx.emails.shortcuts
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ('emails', '0003_alter_email_options'),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.AlterField(
17
+ model_name='email',
18
+ name='mail_from',
19
+ field=models.JSONField(default=pfx.emails.shortcuts.default_mail_from_json, verbose_name='Mail From'),
20
+ ),
21
+ ]
@@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy as _
10
10
  from pfx.emails.exceptions import HasRunningTaskException
11
11
  from pfx.emails.mailjet import Mailjet, Message, MessageResult
12
12
  from pfx.emails.shortcuts import (
13
- default_mail_from,
13
+ default_mail_from_json,
14
14
  default_reply_to,
15
15
  format_json_mail_list,
16
16
  )
@@ -70,7 +70,8 @@ class AbstractEmail(models.Model):
70
70
 
71
71
  send_date = models.DateTimeField(
72
72
  _('Send date'), blank=True, null=True, auto_now_add=True)
73
- mail_from = models.JSONField(_("Mail From"), default=default_mail_from)
73
+ mail_from = models.JSONField(
74
+ _("Mail From"), default=default_mail_from_json)
74
75
  mail_to = models.JSONField(_("Mail To"), default=list)
75
76
  mail_cc = models.JSONField(_("Mail Cc"), blank=True, default=list)
76
77
  mail_bcc = models.JSONField(_("Mail Bcc"), blank=True, default=list)
@@ -6,6 +6,8 @@ from django.core.mail import EmailMultiAlternatives
6
6
  from django.template import loader
7
7
  from django.utils.module_loading import import_string
8
8
 
9
+ from pfx.pfxcore.shortcuts import default_mail_from, default_mail_from_rfc
10
+
9
11
  logger = logging.getLogger(__name__)
10
12
 
11
13
 
@@ -24,9 +26,9 @@ def format_json_mail_list(json):
24
26
  return ', '.join([format_json_mail(a) for a in json])
25
27
 
26
28
 
27
- def default_mail_from():
28
- name = getattr(settings, "PFX_EMAILS_DEFAULT_FROM_NAME", None)
29
- res = {'Email': getattr(settings, "PFX_EMAILS_DEFAULT_FROM_EMAIL", None)}
29
+ def default_mail_from_json():
30
+ name, email = default_mail_from()
31
+ res = {'Email': email}
30
32
  if name:
31
33
  res['Name'] = name
32
34
  return res
@@ -60,10 +62,11 @@ def send_email_message(
60
62
  def get_email(obj):
61
63
  if isinstance(obj, str):
62
64
  return obj
63
- if hasattr(obj, 'full_email'):
65
+ if hasattr(obj, 'get_email_rfc') and callable(obj.get_email_rfc):
66
+ return obj.get_email_rfc()
67
+ if hasattr(obj, 'email_rfc'):
64
68
  return (
65
- obj.full_email() if callable(obj.full_email)
66
- else obj.full_email)
69
+ obj.email_rfc() if callable(obj.email_rfc) else obj.email_rfc)
67
70
  if hasattr(obj, 'email'):
68
71
  return obj.email() if callable(obj.email) else obj.email
69
72
  raise RuntimeError(f"Invalid recipient: {obj}")
@@ -88,7 +91,7 @@ def send_email_message(
88
91
  email = EmailMultiAlternatives(
89
92
  subject=subject,
90
93
  body=text_body,
91
- from_email=from_email or format_json_mail(default_mail_from()),
94
+ from_email=from_email or default_mail_from_rfc(),
92
95
  to=to_email,
93
96
  reply_to=reply_to,
94
97
  headers=headers or {}
@@ -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-07-29 14:36+0200\n"
10
+ "POT-Creation-Date: 2026-07-30 09:14+0200\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -66,13 +66,13 @@ msgstr ""
66
66
  msgid "Your {site_name} verification code: {otp_code}"
67
67
  msgstr "Votre code pour {site_name} : {otp_code}"
68
68
 
69
- #: models/abstract_pfx_base_user.py:58
70
- msgid "user"
71
- msgstr "utilisateur"
69
+ #: models/abstract_pfx_base_user.py:89 models/mfa_device.py:20
70
+ msgid "User"
71
+ msgstr "Utilisateur"
72
72
 
73
- #: models/abstract_pfx_base_user.py:59
74
- msgid "users"
75
- msgstr "utilisateurs"
73
+ #: models/abstract_pfx_base_user.py:90
74
+ msgid "Users"
75
+ msgstr "Utilisateurs"
76
76
 
77
77
  #: models/attachment_mixin.py:25
78
78
  msgid "File"
@@ -98,10 +98,6 @@ msgstr "Login banni"
98
98
  msgid "Login bans"
99
99
  msgstr "Login bannis"
100
100
 
101
- #: models/mfa_device.py:20
102
- msgid "User"
103
- msgstr "Utilisateur"
104
-
105
101
  #: models/mfa_device.py:22
106
102
  msgid "Backend"
107
103
  msgstr "Backend"
@@ -276,11 +272,11 @@ msgstr "Bienvenue sur %(site_name)s."
276
272
  msgid "Welcome on %(site_name)s"
277
273
  msgstr "Bienvenue sur %(site_name)s"
278
274
 
279
- #: views/authentication_views.py:84
275
+ #: views/authentication_views.py:87
280
276
  msgid "Login failed"
281
277
  msgstr "La connexion a échoué"
282
278
 
283
- #: views/authentication_views.py:93
279
+ #: views/authentication_views.py:96
284
280
  #, python-brace-format
285
281
  msgid ""
286
282
  "Your connection is temporarily disabled after several unsuccessful attempts, "
@@ -289,31 +285,31 @@ msgstr ""
289
285
  "Votre connexion est temporairement désactivée après plusieurs tentatives "
290
286
  "infructueuses, veuillez réessayer dans {seconds} secondes."
291
287
 
292
- #: views/authentication_views.py:185
288
+ #: views/authentication_views.py:192
293
289
  msgid "Successful login"
294
290
  msgstr "Connexion réussie"
295
291
 
296
- #: views/authentication_views.py:259 views/authentication_views.py:427
292
+ #: views/authentication_views.py:267 views/authentication_views.py:435
297
293
  msgid "password updated successfully"
298
294
  msgstr "le mot de passe a été mis à jour avec succès"
299
295
 
300
- #: views/authentication_views.py:264
296
+ #: views/authentication_views.py:272
301
297
  msgid "Incorrect password"
302
298
  msgstr "Mot de passe incorrect"
303
299
 
304
- #: views/authentication_views.py:267 views/authentication_views.py:436
300
+ #: views/authentication_views.py:275 views/authentication_views.py:444
305
301
  msgid "Empty password is not allowed"
306
302
  msgstr "Un mot de passe vide n’est pas autorisé"
307
303
 
308
- #: views/authentication_views.py:356
304
+ #: views/authentication_views.py:364
309
305
  msgid "User and token are valid"
310
306
  msgstr "L’utilisateur et le token sont valides"
311
307
 
312
- #: views/authentication_views.py:358
308
+ #: views/authentication_views.py:366
313
309
  msgid "User or token is invalid"
314
310
  msgstr "L’utilisateur ou le token est invalide"
315
311
 
316
- #: views/authentication_views.py:633
312
+ #: views/authentication_views.py:637
317
313
  msgid ""
318
314
  "If the email address you entered is correct, you will receive an email from "
319
315
  "us with instructions to reset your password."
@@ -403,33 +399,3 @@ msgstr "{model} {obj} modifié."
403
399
  #, python-brace-format
404
400
  msgid "{model} {obj} deleted."
405
401
  msgstr "{model} {obj} supprimé."
406
-
407
- #~ msgid "OTP secret token"
408
- #~ msgstr "Jeton secret OTP"
409
-
410
- #~ msgid "Temporary OTP secret token"
411
- #~ msgstr "Jeton secret OTP temporaire"
412
-
413
- #~ msgid "Temporary SMS phone number"
414
- #~ msgstr "Numéro de téléphone temporaire (SMS)"
415
-
416
- #~ msgid "Email MFA disabled"
417
- #~ msgstr "MFA par email désactivé"
418
-
419
- #~ msgid "SMS MFA is already enabled"
420
- #~ msgstr "MFA par SMS déjà activé."
421
-
422
- #~ msgid "Authenticator MFA is already enabled"
423
- #~ msgstr "MFA par application déjà activé"
424
-
425
- #~ msgid "Authenticator MFA disabled"
426
- #~ msgstr "MFA par application activée"
427
-
428
- #~ msgid "A new authentication code has been sent by email."
429
- #~ msgstr "Un nouveau code d’authentification a été envoyé par e-mail."
430
-
431
- #~ msgid "OTP enabled"
432
- #~ msgstr "OTP activé"
433
-
434
- #~ msgid "OTP disabled"
435
- #~ msgstr "OTP désactivé"
@@ -0,0 +1,22 @@
1
+ # Generated by Django 4.2.30 on 2026-07-30 01:07
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations
5
+
6
+ import pfx.pfxcore.models.abstract_pfx_base_user
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ('pfxcore', '0005_mfadevice_mfadevice_mfa_device_unique_backend'),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.AlterModelManagers(
17
+ name='pfxuser',
18
+ managers=[
19
+ ('objects', pfx.pfxcore.models.abstract_pfx_base_user.PFXUserManager()),
20
+ ],
21
+ ),
22
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.30 on 2026-07-30 02:26
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('pfxcore', '0006_alter_pfxuser_managers'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterModelOptions(
15
+ name='pfxuser',
16
+ options={'verbose_name': 'User', 'verbose_name_plural': 'Users'},
17
+ ),
18
+ ]
@@ -1,13 +1,27 @@
1
1
  from django.contrib.auth.models import (
2
2
  AbstractBaseUser,
3
3
  AbstractUser,
4
+ BaseUserManager,
4
5
  PermissionsMixin,
6
+ UserManager,
5
7
  )
6
8
  from django.utils.translation import gettext_lazy as _
7
9
 
8
10
  from .pfx_models import PFXModelMixin
9
11
 
10
12
 
13
+ class PFXBaseUserManager(BaseUserManager):
14
+ def get_by_natural_key(self, username):
15
+ crit = self.model.USERNAME_FIELD
16
+ if not self.model.is_username_case_sensitive():
17
+ crit = f'{crit}__iexact'
18
+ return self.get(**{crit: username})
19
+
20
+
21
+ class PFXUserManager(PFXBaseUserManager, UserManager):
22
+ pass
23
+
24
+
11
25
  class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
12
26
  """The base abstract user for PFX."""
13
27
 
@@ -17,6 +31,14 @@ class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
17
31
  def __str__(self):
18
32
  return self.get_username()
19
33
 
34
+ def get_email_name(self):
35
+ return f"{self}"
36
+
37
+ def get_email_rfc(self):
38
+ name = self.get_email_name()
39
+ email = getattr(self, self.get_email_field_name())
40
+ return f'"{name}" <{email}>'
41
+
20
42
  def auth_json_repr(self, **kw):
21
43
  res = self.json_repr(
22
44
  username=self.get_username(),
@@ -30,9 +52,6 @@ class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
30
52
  res['permissions'] = list(self.get_all_permissions())
31
53
  return res
32
54
 
33
- def get_email_rfc(self):
34
- return f'"{self}" <{getattr(self, self.get_email_field_name())}>'
35
-
36
55
  @classmethod
37
56
  def auth_json_repr_schema(cls):
38
57
  return cls.json_repr_schema()
@@ -50,13 +69,25 @@ class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
50
69
  def on_user_set_password(self, first_time=False):
51
70
  pass
52
71
 
72
+ @classmethod
73
+ def is_username_case_sensitive(cls):
74
+ return getattr(cls, 'USERNAME_FIELD_CASE_SENSITIVE', True)
75
+
76
+ @classmethod
77
+ def is_email_case_sensitive(cls):
78
+ if cls.get_email_field_name() == cls.USERNAME_FIELD:
79
+ return cls.is_username_case_sensitive()
80
+ return getattr(cls, 'EMAIL_FIELD_CASE_SENSITIVE', True)
81
+
53
82
 
54
83
  class AbstractPFXUser(AbstractUser, AbstractPFXBaseUser):
55
84
  """The base abstract user for PFX with permissions mixin."""
56
85
 
86
+ objects = PFXUserManager()
87
+
57
88
  class Meta:
58
- verbose_name = _("user")
59
- verbose_name_plural = _("users")
89
+ verbose_name = _("User")
90
+ verbose_name_plural = _("Users")
60
91
  abstract = True
61
92
 
62
93
  def __str__(self):
@@ -125,4 +125,15 @@ class ErrorMessageMixin():
125
125
 
126
126
 
127
127
  class PFXModelMixin(JSONReprMixin, ErrorMessageMixin):
128
- pass
128
+ def extra_clean_fields(self, errors, exclude=...):
129
+ return errors
130
+
131
+ def clean_fields(self, exclude=...):
132
+ errors = {}
133
+ try:
134
+ super().clean_fields(exclude)
135
+ except ValidationError as e:
136
+ e.update_error_dict(errors)
137
+ errors = self.extra_clean_fields(errors, exclude=exclude)
138
+ if errors:
139
+ raise ValidationError(errors)
@@ -174,7 +174,14 @@ def get_system_error_user_message(context=None):
174
174
  return str(settings.PFX_SYSTEM_ERROR_USER_MESSAGE)
175
175
 
176
176
 
177
- def default_from_email_rfc():
177
+ def default_mail_from():
178
178
  return (
179
- f'"{settings.PFX_EMAILS_DEFAULT_FROM_NAME}" '
180
- f'<{settings.PFX_EMAILS_DEFAULT_FROM_EMAIL}>')
179
+ getattr(settings, "PFX_EMAILS_DEFAULT_FROM_NAME", None),
180
+ getattr(settings, "PFX_EMAILS_DEFAULT_FROM_EMAIL", "pfx@localhost"))
181
+
182
+
183
+ def default_mail_from_rfc():
184
+ name, email = default_mail_from()
185
+ if name:
186
+ return f'"{name}" <{email}>'
187
+ return email
@@ -222,9 +222,9 @@ class TestAssertMixin:
222
222
  return reduce(
223
223
  lambda c, k: c[_p(k)], key.split("."), self.get_json(src))
224
224
  except IndexError:
225
- assert False, f"'{key}' index not found in:" + msg
225
+ assert False, f"'{key}' index not found in: {msg}"
226
226
  except KeyError:
227
- assert False, f"'{key}' not found in:" + msg
227
+ assert False, f"'{key}' not found in: {msg}"
228
228
 
229
229
  # assert JSON content at key equals value
230
230
  def assertJE(self, src, key, value, msg=None):
@@ -31,11 +31,7 @@ from pfx.pfxcore.middleware.authentication import JWTTokenDecodeMixin
31
31
  from pfx.pfxcore.models import CacheableMixin
32
32
  from pfx.pfxcore.models.login_ban import LoginBan
33
33
  from pfx.pfxcore.settings import settings
34
- from pfx.pfxcore.shortcuts import (
35
- default_from_email_rfc,
36
- delete_token_cookie,
37
- f,
38
- )
34
+ from pfx.pfxcore.shortcuts import default_mail_from_rfc, delete_token_cookie, f
39
35
 
40
36
  from .rest_views import (
41
37
  BaseRestView,
@@ -66,6 +62,13 @@ def token_validity(preset):
66
62
  return timedelta(**presets[preset])
67
63
 
68
64
 
65
+ def get_users_by_email(email):
66
+ email_crit = UserModel.get_email_field_name()
67
+ if not UserModel.is_email_case_sensitive():
68
+ email_crit = f'{email_crit}__iexact'
69
+ return UserModel._default_manager.filter(**{email_crit: email})
70
+
71
+
69
72
  @rest_view("/auth")
70
73
  class AuthenticationView(
71
74
  ModelMixin, BodyMixin, JWTTokenDecodeMixin, BaseRestView):
@@ -146,11 +149,15 @@ class AuthenticationView(
146
149
  """
147
150
  data = self.deserialize_body()
148
151
  username = data.get('username')
152
+ if (isinstance(username, str) and
153
+ not UserModel.is_username_case_sensitive()):
154
+ username = username.lower()
149
155
  ban_dt = LoginBan.objects.is_ban(username)
150
156
  if ban_dt:
151
157
  return self.login_ban_response(ban_dt)
152
- user = authenticate(self.request, username=username,
153
- password=data.get('password'))
158
+ user = authenticate(
159
+ self.request, username=username,
160
+ password=data.get('password'))
154
161
  if isinstance(user, CacheableMixin):
155
162
  user.cache_delete()
156
163
  if user is None:
@@ -242,14 +249,15 @@ class AuthenticationView(
242
249
  format: password
243
250
  """
244
251
  data = self.deserialize_body()
245
- user = authenticate(self.request,
246
- username=self.request.user.get_username(),
247
- password=data.get('old_password'))
252
+ user = authenticate(
253
+ self.request,
254
+ username=self.request.user.get_username(),
255
+ password=data.get('old_password'))
248
256
  errors = dict()
249
257
  try:
250
258
  if user is not None and data.get('new_password'):
251
- password_validation.validate_password(data['new_password'],
252
- user)
259
+ password_validation.validate_password(
260
+ data['new_password'], user)
253
261
  user.set_password(data.get('new_password'))
254
262
  user.save()
255
263
 
@@ -526,7 +534,7 @@ class SendMessageTokenMixin:
526
534
  subject = ''.join(subject.splitlines())
527
535
  body = loader.render_to_string(self.email_template_name, data)
528
536
  email_message = EmailMultiAlternatives(
529
- subject, body, self.from_email or default_from_email_rfc(),
537
+ subject, body, self.from_email or default_mail_from_rfc(),
530
538
  [user.get_email_rfc()])
531
539
  if self.html_email_template_name is not None:
532
540
  html_email = loader.render_to_string(
@@ -623,11 +631,7 @@ class ForgottenPasswordView(SendMessageTokenMixin, BodyMixin, BaseRestView):
623
631
  return JsonResponse(
624
632
  ValidationError(dict(email=e.error_list)), status=422)
625
633
  if email:
626
- try:
627
- user = UserModel._default_manager.get(email=email)
628
- except UserModel.DoesNotExist:
629
- user = None
630
- if user is not None:
634
+ for user in get_users_by_email(email):
631
635
  self.send_token_message(user)
632
636
  return JsonResponse({
633
637
  'message': _('If the email address you entered is correct, '