django-pfx 1.4.dev72__tar.gz → 1.4.dev76__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 (183) hide show
  1. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/PKG-INFO +1 -1
  2. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/django_pfx.egg-info/PKG-INFO +1 -1
  3. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/django_pfx.egg-info/SOURCES.txt +3 -1
  4. django_pfx-1.4.dev76/pfx/pfxcore/apps.py +31 -0
  5. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/default_settings.py +3 -0
  6. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +18 -18
  7. django_pfx-1.4.dev76/pfx/pfxcore/migrations/__init__.py +3 -0
  8. django_pfx-1.4.dev76/pfx/pfxcore/migrations/operations/__init__.py +1 -0
  9. django_pfx-1.4.dev76/pfx/pfxcore/migrations/operations/permissions.py +87 -0
  10. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/shortcuts.py +5 -2
  11. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/authentication_views.py +4 -2
  12. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/fields.py +5 -3
  13. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/rest_views.py +19 -7
  14. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/migrations/0001_initial.py +2 -1
  15. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/__init__.py +1 -0
  16. django_pfx-1.4.dev76/tests/tests/test_post_migrate_groups_update.py +79 -0
  17. django_pfx-1.4.dev72/pfx/pfxcore/apps.py +0 -9
  18. django_pfx-1.4.dev72/tests/migrations/0002_alter_author_options.py +0 -18
  19. django_pfx-1.4.dev72/tests_custom_user/settings/__init__.py +0 -0
  20. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/.gitignore +0 -0
  21. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/.gitlab-ci.yml +0 -0
  22. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/.pre-commit-config.yaml +0 -0
  23. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/LICENSE +0 -0
  24. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/MANIFEST.in +0 -0
  25. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/README.md +0 -0
  26. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/django_pfx.egg-info/dependency_links.txt +0 -0
  27. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/django_pfx.egg-info/requires.txt +0 -0
  28. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/django_pfx.egg-info/top_level.txt +0 -0
  29. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/Makefile +0 -0
  30. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/conf.py +0 -0
  31. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/index.rst +0 -0
  32. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/api.views.rst +0 -0
  33. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/authentication.md +0 -0
  34. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/decorator.md +0 -0
  35. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/generate_openapi.md +0 -0
  36. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/getting_started.md +0 -0
  37. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/internationalisation.md +0 -0
  38. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/model.md +0 -0
  39. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/pfx_views.md +0 -0
  40. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/profiling.md +0 -0
  41. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/settings.md +0 -0
  42. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/doc/source/testing.md +0 -0
  43. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/img/pfx.png +0 -0
  44. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/img/pfx.svg +0 -0
  45. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/make_messages +0 -0
  46. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/manage.py +0 -0
  47. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/__init__.py +0 -0
  48. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/__init__.py +0 -0
  49. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/apidoc/__init__.py +0 -0
  50. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/apidoc/parameters.py +0 -0
  51. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/apidoc/schema.py +0 -0
  52. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/apidoc/tags.py +0 -0
  53. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/decorator/__init__.py +0 -0
  54. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/decorator/rest.py +0 -0
  55. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/exceptions.py +0 -0
  56. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/fields.py +0 -0
  57. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/http/__init__.py +0 -0
  58. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/http/json_response.py +0 -0
  59. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  60. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/management/__init__.py +0 -0
  61. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/management/commands/__init__.py +0 -0
  62. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  63. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/management/commands/profile.py +0 -0
  64. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/middleware/__init__.py +0 -0
  65. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/middleware/authentication.py +0 -0
  66. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/middleware/locale.py +0 -0
  67. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/middleware/profiling.py +0 -0
  68. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  69. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  70. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  71. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/__init__.py +0 -0
  72. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
  73. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/cache_mixins.py +0 -0
  74. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/login_ban.py +0 -0
  75. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/not_null_fields.py +0 -0
  76. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
  77. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/pfx_models.py +0 -0
  78. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/pfx_user.py +0 -0
  79. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  80. {django_pfx-1.4.dev72/pfx/pfxcore/migrations → django_pfx-1.4.dev76/pfx/pfxcore/serializers}/__init__.py +0 -0
  81. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/serializers/json.py +0 -0
  82. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/settings.py +0 -0
  83. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/storage/__init__.py +0 -0
  84. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/storage/s3_storage.py +0 -0
  85. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  86. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  87. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  88. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  89. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  90. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  91. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/test.py +0 -0
  92. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/urls.py +0 -0
  93. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/__init__.py +0 -0
  94. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/filters_views.py +0 -0
  95. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/locale_views.py +0 -0
  96. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  97. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  98. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/groups.py +0 -0
  99. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  100. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  101. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  102. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  103. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  104. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  105. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  106. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  107. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  108. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset.py +0 -0
  109. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  110. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  111. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  112. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  113. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  114. {django_pfx-1.4.dev72/pfx/pfxcore/serializers → django_pfx-1.4.dev76/pfx/settings}/__init__.py +0 -0
  115. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pfx/settings/dev.py +0 -0
  116. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/pyproject.toml +0 -0
  117. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/requirements.txt +0 -0
  118. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/serve-doc +0 -0
  119. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/setup.cfg +0 -0
  120. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/setup.py +0 -0
  121. {django_pfx-1.4.dev72/pfx/settings → django_pfx-1.4.dev76/tests}/__init__.py +0 -0
  122. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  123. {django_pfx-1.4.dev72/tests → django_pfx-1.4.dev76/tests/migrations}/__init__.py +0 -0
  124. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/models.py +0 -0
  125. {django_pfx-1.4.dev72/tests/migrations → django_pfx-1.4.dev76/tests/settings}/__init__.py +0 -0
  126. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/settings/ci.py +0 -0
  127. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/settings/common.py +0 -0
  128. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/settings/dev.py +0 -0
  129. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/settings/dev_custom_example.py +0 -0
  130. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/settings/dev_default.py +0 -0
  131. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/basic_api_errors.py +0 -0
  132. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/basic_api_test.py +0 -0
  133. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_api_doc.py +0 -0
  134. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_api_doc_search.py +0 -0
  135. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_auth_api.py +0 -0
  136. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_body_mixin.py +0 -0
  137. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_cache.py +0 -0
  138. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_client.py +0 -0
  139. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_fields.py +0 -0
  140. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_filters.py +0 -0
  141. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_locale_api.py +0 -0
  142. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_perm_tests.py +0 -0
  143. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_permissions.py +0 -0
  144. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_perms_api.py +0 -0
  145. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_profiling_middleware.py +0 -0
  146. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_settings.py +0 -0
  147. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_shortcuts.py +0 -0
  148. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_timezone_middleware.py +0 -0
  149. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_tools.py +0 -0
  150. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_user_queryset.py +0 -0
  151. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_view_decorators.py +0 -0
  152. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/tests/test_view_fields.py +0 -0
  153. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/urls.py +0 -0
  154. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests/views.py +0 -0
  155. {django_pfx-1.4.dev72/tests/settings → django_pfx-1.4.dev76/tests_base_user}/__init__.py +0 -0
  156. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/migrations/0001_initial.py +0 -0
  157. {django_pfx-1.4.dev72/tests_base_user → django_pfx-1.4.dev76/tests_base_user/migrations}/__init__.py +0 -0
  158. {django_pfx-1.4.dev72/tests_base_user/migrations → django_pfx-1.4.dev76/tests_base_user/settings}/__init__.py +0 -0
  159. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/settings/ci.py +0 -0
  160. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/settings/common.py +0 -0
  161. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/settings/dev.py +0 -0
  162. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/settings/dev_custom_example.py +0 -0
  163. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/settings/dev_default.py +0 -0
  164. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/tests/__init__.py +0 -0
  165. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/tests/test_api.py +0 -0
  166. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/tests/test_auth_api.py +0 -0
  167. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/urls.py +0 -0
  168. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_base_user/views.py +0 -0
  169. {django_pfx-1.4.dev72/tests_base_user/settings → django_pfx-1.4.dev76/tests_custom_user}/__init__.py +0 -0
  170. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/migrations/0001_initial.py +0 -0
  171. {django_pfx-1.4.dev72/tests_custom_user → django_pfx-1.4.dev76/tests_custom_user/migrations}/__init__.py +0 -0
  172. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/models.py +0 -0
  173. {django_pfx-1.4.dev72/tests_custom_user/migrations → django_pfx-1.4.dev76/tests_custom_user/settings}/__init__.py +0 -0
  174. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/settings/ci.py +0 -0
  175. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/settings/common.py +0 -0
  176. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/settings/dev.py +0 -0
  177. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/settings/dev_custom_example.py +0 -0
  178. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/settings/dev_default.py +0 -0
  179. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/tests/__init__.py +0 -0
  180. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/tests/test_api.py +0 -0
  181. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/tests/test_auth_api.py +0 -0
  182. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/urls.py +0 -0
  183. {django_pfx-1.4.dev72 → django_pfx-1.4.dev76}/tests_custom_user/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev72
3
+ Version: 1.4.dev76
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.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev72
3
+ Version: 1.4.dev76
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
@@ -64,6 +64,8 @@ pfx/pfxcore/migrations/0001_initial.py
64
64
  pfx/pfxcore/migrations/0002_pfxpermissionsuser.py
65
65
  pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py
66
66
  pfx/pfxcore/migrations/__init__.py
67
+ pfx/pfxcore/migrations/operations/__init__.py
68
+ pfx/pfxcore/migrations/operations/permissions.py
67
69
  pfx/pfxcore/models/__init__.py
68
70
  pfx/pfxcore/models/abstract_pfx_base_user.py
69
71
  pfx/pfxcore/models/cache_mixins.py
@@ -115,7 +117,6 @@ tests/urls.py
115
117
  tests/views.py
116
118
  tests/locale/fr/LC_MESSAGES/django.po
117
119
  tests/migrations/0001_initial.py
118
- tests/migrations/0002_alter_author_options.py
119
120
  tests/migrations/__init__.py
120
121
  tests/settings/__init__.py
121
122
  tests/settings/ci.py
@@ -138,6 +139,7 @@ tests/tests/test_locale_api.py
138
139
  tests/tests/test_perm_tests.py
139
140
  tests/tests/test_permissions.py
140
141
  tests/tests/test_perms_api.py
142
+ tests/tests/test_post_migrate_groups_update.py
141
143
  tests/tests/test_profiling_middleware.py
142
144
  tests/tests/test_settings.py
143
145
  tests/tests/test_shortcuts.py
@@ -0,0 +1,31 @@
1
+ import logging
2
+
3
+ from django.apps import AppConfig
4
+ from django.db.models.signals import post_migrate
5
+
6
+ from pfx.pfxcore.shortcuts import permissions, settings
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ def update_groups_permissions(sender, **kwargs):
12
+ from django.contrib.auth.models import Group
13
+ groups = {g.name: g for g in Group.objects.all()}
14
+
15
+ for name, perms in settings.PFX_AUTH_GROUPS.items():
16
+ created = name not in groups
17
+ group = Group.objects.create(name=name) if created else groups[name]
18
+ if created or not settings.PFX_AUTH_GROUPS_CREATE_ONLY:
19
+ group.permissions.set(permissions(*perms))
20
+
21
+ if not settings.PFX_AUTH_GROUPS_CREATE_ONLY:
22
+ names = groups.keys() - settings.PFX_AUTH_GROUPS.keys()
23
+ Group.objects.filter(name__in=names).delete()
24
+
25
+
26
+ class PfxCoreConfig(AppConfig):
27
+ name = 'pfx.pfxcore'
28
+
29
+ def ready(self):
30
+ if settings.PFX_AUTH_GROUPS is not None:
31
+ post_migrate.connect(update_groups_permissions, sender=self)
@@ -30,3 +30,6 @@ STORAGE_S3_AWS_PUT_URL_EXPIRE = None
30
30
  STORAGE_S3_AWS_GET_URL_EXPIRE = None
31
31
 
32
32
  PFX_TEST_MODE = False
33
+
34
+ PFX_AUTH_GROUPS = None
35
+ PFX_AUTH_GROUPS_CREATE_ONLY = False
@@ -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: 2025-01-21 18:35+0100\n"
10
+ "POT-Creation-Date: 2025-01-29 12:33+0100\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -103,7 +103,7 @@ msgstr "Compte HOTP"
103
103
  msgid "HOTP expiry"
104
104
  msgstr "Expiration HOTP"
105
105
 
106
- #: models/otp_user_mixin.py:29 views/authentication_views.py:491
106
+ #: models/otp_user_mixin.py:29 views/authentication_views.py:492
107
107
  msgid "OTP enabled"
108
108
  msgstr "OTP activé"
109
109
 
@@ -204,7 +204,7 @@ msgstr "Bienvenue sur %(site_name)s."
204
204
  msgid "Welcome on %(site_name)s"
205
205
  msgstr "Bienvenue sur %(site_name)s"
206
206
 
207
- #: views/authentication_views.py:81
207
+ #: views/authentication_views.py:82
208
208
  #, python-brace-format
209
209
  msgid ""
210
210
  "Your connection is temporarily disabled after several unsuccessful attempts, "
@@ -213,43 +213,43 @@ msgstr ""
213
213
  "Votre connexion est temporairement désactivée après plusieurs tentatives "
214
214
  "infructueuses, veuillez réessayer dans {seconds} secondes."
215
215
 
216
- #: views/authentication_views.py:173
216
+ #: views/authentication_views.py:174
217
217
  msgid "Successful login"
218
218
  msgstr "Connexion réussie"
219
219
 
220
- #: views/authentication_views.py:243 views/authentication_views.py:408
220
+ #: views/authentication_views.py:244 views/authentication_views.py:409
221
221
  msgid "password updated successfully"
222
222
  msgstr "le mot de passe a été mis à jour avec succès"
223
223
 
224
- #: views/authentication_views.py:248
224
+ #: views/authentication_views.py:249
225
225
  msgid "Incorrect password"
226
226
  msgstr "Mot de passe incorrect"
227
227
 
228
- #: views/authentication_views.py:251 views/authentication_views.py:417
228
+ #: views/authentication_views.py:252 views/authentication_views.py:418
229
229
  msgid "Empty password is not allowed"
230
230
  msgstr "Un mot de passe vide n’est pas autorisé"
231
231
 
232
- #: views/authentication_views.py:342
232
+ #: views/authentication_views.py:343
233
233
  msgid "User and token are valid"
234
234
  msgstr "L'utilisateur et le token sont valides"
235
235
 
236
- #: views/authentication_views.py:344
236
+ #: views/authentication_views.py:345
237
237
  msgid "User or token is invalid"
238
238
  msgstr "L'utilisateur ou le token est invalide"
239
239
 
240
- #: views/authentication_views.py:451
240
+ #: views/authentication_views.py:452
241
241
  msgid "OTP is already enabled"
242
242
  msgstr "OTP est déjà activé"
243
243
 
244
- #: views/authentication_views.py:492 views/authentication_views.py:528
244
+ #: views/authentication_views.py:493 views/authentication_views.py:529
245
245
  msgid "Invalid code"
246
246
  msgstr "Code invalide"
247
247
 
248
- #: views/authentication_views.py:527
248
+ #: views/authentication_views.py:528
249
249
  msgid "OTP disabled"
250
250
  msgstr "OTP désactivé"
251
251
 
252
- #: views/authentication_views.py:787
252
+ #: views/authentication_views.py:789
253
253
  msgid ""
254
254
  "If the email address you entered is correct, you will receive an email from "
255
255
  "us with instructions to reset your password."
@@ -258,7 +258,7 @@ msgstr ""
258
258
  "un courrier électronique de notre part contenant des instructions pour "
259
259
  "réinitialiser votre mot de passe."
260
260
 
261
- #: views/authentication_views.py:861
261
+ #: views/authentication_views.py:863
262
262
  msgid "A new authentication code has been sent by email."
263
263
  msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
264
264
 
@@ -273,21 +273,21 @@ msgid "{obj} cannot be deleted because it is referenced by other objects."
273
273
  msgstr ""
274
274
  "{obj} ne peut pas être supprimé car il est référencé par d’autres objets."
275
275
 
276
- #: views/rest_views.py:342
276
+ #: views/rest_views.py:327
277
277
  #, python-brace-format
278
278
  msgid "{model} {obj} created."
279
279
  msgstr "{model} {obj} créé."
280
280
 
281
- #: views/rest_views.py:343
281
+ #: views/rest_views.py:328
282
282
  #, python-brace-format
283
283
  msgid "{model} {obj} updated."
284
284
  msgstr "{model} {obj} modifié."
285
285
 
286
- #: views/rest_views.py:1141
286
+ #: views/rest_views.py:1153
287
287
  #, python-brace-format
288
288
  msgid "{model} {obj} deleted."
289
289
  msgstr "{model} {obj} supprimé."
290
290
 
291
- #: views/rest_views.py:1240 views/rest_views.py:1280
291
+ #: views/rest_views.py:1252 views/rest_views.py:1292
292
292
  msgid "Unexpected storage error"
293
293
  msgstr "Erreur de stockage inattendue"
@@ -0,0 +1,3 @@
1
+ from django.db.migrations import *
2
+
3
+ from .operations import *
@@ -0,0 +1 @@
1
+ from .permissions import CreateGroup, DeleteGroup, RenameGroup
@@ -0,0 +1,87 @@
1
+ from django.db.migrations.operations.base import Operation
2
+
3
+
4
+ class GroupPermsOperation(Operation):
5
+ def state_forwards(self, app_label, state):
6
+ pass
7
+
8
+
9
+ class CreateGroup(GroupPermsOperation):
10
+ """Create a group."""
11
+
12
+ def __init__(self, name):
13
+ self.group_name = name
14
+
15
+ def deconstruct(self):
16
+ return (self.__class__.__qualname__, [self.group_name], {})
17
+
18
+ def database_forwards(
19
+ self, app_label, schema_editor, from_state, to_state):
20
+ Group = to_state.apps.get_model('auth', 'Group')
21
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
22
+ Group.objects.create(name=self.group_name)
23
+
24
+ def database_backwards(
25
+ self, app_label, schema_editor, from_state, to_state):
26
+ Group = to_state.apps.get_model('auth', 'Group')
27
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
28
+ Group.objects.get(name=self.group_name).delete()
29
+
30
+ def describe(self):
31
+ return (f"Create group {self.group_name}")
32
+
33
+
34
+ class DeleteGroup(GroupPermsOperation):
35
+ """Delete a group."""
36
+
37
+ def __init__(self, name):
38
+ self.group_name = name
39
+
40
+ def deconstruct(self):
41
+ return (self.__class__.__qualname__, [self.group_name], {})
42
+
43
+ def database_forwards(
44
+ self, app_label, schema_editor, from_state, to_state):
45
+ Group = to_state.apps.get_model('auth', 'Group')
46
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
47
+ Group.objects.get(name=self.group_name).delete()
48
+
49
+ def database_backwards(
50
+ self, app_label, schema_editor, from_state, to_state):
51
+ Group = to_state.apps.get_model('auth', 'Group')
52
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
53
+ Group.objects.create(name=self.group_name)
54
+
55
+ def describe(self):
56
+ return (f"Create group {self.group_name}")
57
+
58
+
59
+ class RenameGroup(GroupPermsOperation):
60
+ """Rename a group."""
61
+
62
+ def __init__(self, old_name, new_name):
63
+ self.group_old_name = old_name
64
+ self.group_new_name = new_name
65
+
66
+ def deconstruct(self):
67
+ return (self.__class__.__qualname__, [
68
+ self.group_old_name, self.group_new_name], {})
69
+
70
+ def database_forwards(
71
+ self, app_label, schema_editor, from_state, to_state):
72
+ Group = to_state.apps.get_model('auth', 'Group')
73
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
74
+ group = Group.objects.get(name=self.group_old_name)
75
+ group.name = self.group_new_name
76
+ group.save()
77
+
78
+ def database_backwards(
79
+ self, app_label, schema_editor, from_state, to_state):
80
+ Group = to_state.apps.get_model('auth', 'Group')
81
+ if self.allow_migrate_model(schema_editor.connection.alias, Group):
82
+ group = Group.objects.get(name=self.group_new_name)
83
+ group.name = self.group_old_name
84
+ group.save()
85
+
86
+ def describe(self):
87
+ return (f"Rename group {self.group_old_name} to {self.group_new_name}")
@@ -128,8 +128,11 @@ def permissions(*perms):
128
128
  pks = set()
129
129
  for perm in perms:
130
130
  app_label, codename = perm.split('.')
131
- pks.add(Permission.objects.get(
132
- codename=codename, content_type__app_label=app_label).pk)
131
+ try:
132
+ pks.add(Permission.objects.get(
133
+ codename=codename, content_type__app_label=app_label).pk)
134
+ except Permission.DoesNotExist:
135
+ raise Exception(f"Permission {perm} does not exists.")
133
136
  return Permission.objects.filter(pk__in=pks)
134
137
 
135
138
 
@@ -10,6 +10,7 @@ from django.contrib.auth.tokens import default_token_generator
10
10
  from django.core.exceptions import ValidationError
11
11
  from django.core.mail import EmailMultiAlternatives
12
12
  from django.core.validators import validate_email
13
+ from django.db import transaction
13
14
  from django.template import loader
14
15
  from django.utils.decorators import method_decorator
15
16
  from django.utils.encoding import force_bytes
@@ -724,8 +725,9 @@ class SignupView(SendMessageTokenMixin, CreateRestViewMixin, BaseRestView):
724
725
  super().validate(obj, **kwargs)
725
726
 
726
727
  def is_valid(self, obj, created=True, **kwargs):
727
- r = super().is_valid(obj, created, **kwargs)
728
- self.send_token_message(obj)
728
+ with transaction.atomic():
729
+ r = super().is_valid(obj, created, **kwargs)
730
+ self.send_token_message(obj)
729
731
  return r
730
732
 
731
733
 
@@ -117,7 +117,8 @@ class ViewField:
117
117
  dict(label=_(v), value=k) for k, v in self.choices.items()]
118
118
  if self.related_model:
119
119
  res['model'] = self.related_model._meta.label
120
- res['api'] = self.related_model_api or self.related_model.api
120
+ res['api'] = self.related_model_api or getattr(
121
+ self.related_model, 'api', None)
121
122
  res['readonly'] = dict(
122
123
  post=self.readonly_create,
123
124
  put=self.readonly_update)
@@ -362,14 +363,15 @@ class VF:
362
363
  self, name, verbose_name=None, field_type=None, alias=None,
363
364
  readonly=False, readonly_create=False, readonly_update=False,
364
365
  choices=None, select_related=None, prefetch_related=None,
365
- json_repr=None):
366
+ json_repr=None, related_model=None, related_model_api=None):
366
367
  self.kwargs = dict(
367
368
  name=name, verbose_name=verbose_name, field_type=field_type,
368
369
  alias=alias,
369
370
  readonly=readonly, readonly_create=readonly_create,
370
371
  readonly_update=readonly_update, choices=choices,
371
372
  select_related=select_related, prefetch_related=prefetch_related,
372
- json_repr=json_repr)
373
+ json_repr=json_repr, related_model=related_model,
374
+ related_model_api=related_model_api)
373
375
 
374
376
  def to_field(self, model):
375
377
  return ViewField.from_name(model, **self.kwargs)
@@ -314,6 +314,23 @@ class ModelResponseMixin(ModelMixin):
314
314
  """
315
315
  obj.full_clean(**kwargs)
316
316
 
317
+ def is_valid_response_meta(self, obj, created=False):
318
+ """Prepare the defaut meta for is_valid responce.
319
+
320
+ :param obj: The object instance
321
+ :param created: If object instance is created
322
+ :returns: The JSON response
323
+ :rtype: :class:`JsonResponse`
324
+ """
325
+ message = (
326
+ created and
327
+ _("{model} {obj} created.") or
328
+ _("{model} {obj} updated."))
329
+ return dict(
330
+ created=created,
331
+ message=f(
332
+ message, model=self.model_name, obj=object))
333
+
317
334
  def is_valid(self, obj, created=False, rel_data=None):
318
335
  """Persist an object instance changes and build default response.
319
336
 
@@ -337,14 +354,9 @@ class ModelResponseMixin(ModelMixin):
337
354
  getattr(obj, k).set(v)
338
355
  else:
339
356
  obj.save()
340
- message = (
341
- created and
342
- _("{model} {obj} created.") or
343
- _("{model} {obj} updated."))
344
- object = self.get_object(pk=obj.pk)
357
+ obj = self.get_object(pk=obj.pk)
345
358
  return self.response(
346
- object, message=f(
347
- message, model=self.model_name, obj=object))
359
+ obj, **self.is_valid_response_meta(obj, created=created))
348
360
 
349
361
  def is_invalid(self, obj, errors):
350
362
  """Build a 422 response for invalid object instance.
@@ -1,4 +1,4 @@
1
- # Generated by Django 4.2.17 on 2025-01-21 08:32
1
+ # Generated by Django 4.2.17 on 2025-01-22 07:34
2
2
  # flake8: noqa
3
3
 
4
4
  import django.contrib.auth.models
@@ -40,6 +40,7 @@ class Migration(migrations.Migration):
40
40
  'verbose_name': 'Author',
41
41
  'verbose_name_plural': 'Authors',
42
42
  'ordering': ['last_name', 'first_name', 'pk'],
43
+ 'permissions': [('can_customize_author', 'Can customize author')],
43
44
  },
44
45
  bases=(pfx.pfxcore.models.cache_mixins.CacheableMixin, pfx.pfxcore.models.pfx_models.JSONReprMixin, models.Model),
45
46
  ),
@@ -12,6 +12,7 @@ from .test_locale_api import LocaleAPITest
12
12
  from .test_perm_tests import PermTestsTest
13
13
  from .test_permissions import TestPermissions
14
14
  from .test_perms_api import PermsAPITest
15
+ from .test_post_migrate_groups_update import TestPostMigrateGroupsUpdate
15
16
  from .test_profiling_middleware import ProfilingMiddlewareTest
16
17
  from .test_settings import TestSettings
17
18
  from .test_shortcuts import ShortcutTest
@@ -0,0 +1,79 @@
1
+ from django.contrib.auth.models import Group
2
+ from django.test import TestCase
3
+ from django.test.utils import override_settings
4
+
5
+ from pfx.pfxcore.apps import update_groups_permissions
6
+ from pfx.pfxcore.test import TestAssertMixin
7
+
8
+
9
+ class TestPostMigrateGroupsUpdate(TestAssertMixin, TestCase):
10
+
11
+ @override_settings(PFX_AUTH_GROUPS=dict(
12
+ reader=[
13
+ 'tests.view_author',
14
+ ],
15
+ editor=[
16
+ 'tests.view_author',
17
+ 'tests.add_author',
18
+ ]))
19
+ def test_groups(self):
20
+ update_groups_permissions(self)
21
+
22
+ groups = {g.name: g for g in Group.objects.all()}
23
+ self.assertEqual(groups.keys(), {'reader', 'editor'})
24
+ perms = {p.codename for p in groups['reader'].permissions.all()}
25
+ self.assertEqual(perms, {'view_author'})
26
+ perms = {p.codename for p in groups['editor'].permissions.all()}
27
+ self.assertEqual(perms, {'view_author', 'add_author'})
28
+
29
+ with override_settings(
30
+ PFX_AUTH_GROUPS=dict(
31
+ editor=[
32
+ 'tests.view_author',
33
+ 'tests.change_author',
34
+ ],
35
+ new=[])):
36
+ update_groups_permissions(self)
37
+
38
+ groups = {g.name: g for g in Group.objects.all()}
39
+ self.assertEqual(groups.keys(), {'editor', 'new'})
40
+ perms = {p.codename for p in groups['editor'].permissions.all()}
41
+ self.assertEqual(perms, {'view_author', 'change_author'})
42
+ perms = {p.codename for p in groups['new'].permissions.all()}
43
+ self.assertEqual(perms, set())
44
+
45
+ @override_settings(PFX_AUTH_GROUPS=dict(
46
+ reader=[
47
+ 'tests.view_author',
48
+ ],
49
+ editor=[
50
+ 'tests.view_author',
51
+ 'tests.add_author',
52
+ ]), PFX_AUTH_GROUPS_CREATE_ONLY=True)
53
+ def test_groups_create_only(self):
54
+ update_groups_permissions(self)
55
+
56
+ groups = {g.name: g for g in Group.objects.all()}
57
+ self.assertEqual(groups.keys(), {'reader', 'editor'})
58
+ perms = {p.codename for p in groups['reader'].permissions.all()}
59
+ self.assertEqual(perms, {'view_author'})
60
+ perms = {p.codename for p in groups['editor'].permissions.all()}
61
+ self.assertEqual(perms, {'view_author', 'add_author'})
62
+
63
+ with override_settings(
64
+ PFX_AUTH_GROUPS=dict(
65
+ editor=[
66
+ 'tests.view_author',
67
+ 'tests.change_author',
68
+ ],
69
+ new=[])):
70
+ update_groups_permissions(self)
71
+
72
+ groups = {g.name: g for g in Group.objects.all()}
73
+ self.assertEqual(groups.keys(), {'reader', 'editor', 'new'})
74
+ perms = {p.codename for p in groups['reader'].permissions.all()}
75
+ self.assertEqual(perms, {'view_author'})
76
+ perms = {p.codename for p in groups['editor'].permissions.all()}
77
+ self.assertEqual(perms, {'view_author', 'add_author'})
78
+ perms = {p.codename for p in groups['new'].permissions.all()}
79
+ self.assertEqual(perms, set())
@@ -1,9 +0,0 @@
1
- import logging
2
-
3
- from django.apps import AppConfig
4
-
5
- logger = logging.getLogger(__name__)
6
-
7
-
8
- class PfxCoreConfig(AppConfig):
9
- name = 'pfx.pfxcore'
@@ -1,18 +0,0 @@
1
- # Generated by Django 4.2.17 on 2025-01-22 03:31
2
- # flake8: noqa
3
-
4
- from django.db import migrations
5
-
6
-
7
- class Migration(migrations.Migration):
8
-
9
- dependencies = [
10
- ('tests', '0001_initial'),
11
- ]
12
-
13
- operations = [
14
- migrations.AlterModelOptions(
15
- name='author',
16
- options={'ordering': ['last_name', 'first_name', 'pk'], 'permissions': [('can_customize_author', 'Can customize author')], 'verbose_name': 'Author', 'verbose_name_plural': 'Authors'},
17
- ),
18
- ]
File without changes
File without changes
File without changes