django-pfx 1.4.dev68__tar.gz → 1.4.dev70__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 (177) hide show
  1. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.gitlab-ci.yml +6 -3
  2. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.pre-commit-config.yaml +7 -0
  3. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/PKG-INFO +1 -1
  4. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/PKG-INFO +1 -1
  5. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/SOURCES.txt +30 -1
  6. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/manage.py +15 -6
  7. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +19 -11
  8. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/abstract_pfx_base_user.py +10 -0
  9. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_user.py +2 -2
  10. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/authentication_views.py +4 -9
  11. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/migrations/0001_initial.py +1 -14
  12. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/models.py +0 -13
  13. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_client.py +22 -1
  14. django_pfx-1.4.dev70/tests_base_user/__init__.py +0 -0
  15. django_pfx-1.4.dev70/tests_base_user/migrations/0001_initial.py +13 -0
  16. django_pfx-1.4.dev70/tests_base_user/migrations/__init__.py +0 -0
  17. django_pfx-1.4.dev70/tests_base_user/settings/__init__.py +0 -0
  18. django_pfx-1.4.dev70/tests_base_user/settings/ci.py +18 -0
  19. django_pfx-1.4.dev70/tests_base_user/settings/common.py +80 -0
  20. django_pfx-1.4.dev70/tests_base_user/settings/dev.py +13 -0
  21. django_pfx-1.4.dev70/tests_base_user/settings/dev_custom_example.py +28 -0
  22. django_pfx-1.4.dev70/tests_base_user/settings/dev_default.py +12 -0
  23. django_pfx-1.4.dev70/tests_base_user/tests/__init__.py +2 -0
  24. django_pfx-1.4.dev70/tests_base_user/tests/test_api.py +32 -0
  25. django_pfx-1.4.dev70/tests_base_user/tests/test_auth_api.py +59 -0
  26. django_pfx-1.4.dev70/tests_base_user/urls.py +13 -0
  27. django_pfx-1.4.dev70/tests_base_user/views.py +13 -0
  28. django_pfx-1.4.dev70/tests_custom_user/__init__.py +0 -0
  29. django_pfx-1.4.dev70/tests_custom_user/migrations/0001_initial.py +31 -0
  30. django_pfx-1.4.dev70/tests_custom_user/migrations/__init__.py +0 -0
  31. django_pfx-1.4.dev70/tests_custom_user/models.py +18 -0
  32. django_pfx-1.4.dev70/tests_custom_user/settings/__init__.py +0 -0
  33. django_pfx-1.4.dev70/tests_custom_user/settings/ci.py +18 -0
  34. django_pfx-1.4.dev70/tests_custom_user/settings/common.py +80 -0
  35. django_pfx-1.4.dev70/tests_custom_user/settings/dev.py +13 -0
  36. django_pfx-1.4.dev70/tests_custom_user/settings/dev_custom_example.py +28 -0
  37. django_pfx-1.4.dev70/tests_custom_user/settings/dev_default.py +12 -0
  38. django_pfx-1.4.dev70/tests_custom_user/tests/__init__.py +2 -0
  39. django_pfx-1.4.dev70/tests_custom_user/tests/test_api.py +24 -0
  40. django_pfx-1.4.dev70/tests_custom_user/tests/test_auth_api.py +57 -0
  41. django_pfx-1.4.dev70/tests_custom_user/urls.py +13 -0
  42. django_pfx-1.4.dev70/tests_custom_user/views.py +13 -0
  43. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.gitignore +0 -0
  44. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/LICENSE +0 -0
  45. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/MANIFEST.in +0 -0
  46. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/README.md +0 -0
  47. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/dependency_links.txt +0 -0
  48. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/requires.txt +0 -0
  49. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/top_level.txt +0 -0
  50. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/Makefile +0 -0
  51. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/conf.py +0 -0
  52. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/index.rst +0 -0
  53. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/api.views.rst +0 -0
  54. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/authentication.md +0 -0
  55. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/decorator.md +0 -0
  56. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/generate_openapi.md +0 -0
  57. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/getting_started.md +0 -0
  58. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/internationalisation.md +0 -0
  59. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/model.md +0 -0
  60. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/pfx_views.md +0 -0
  61. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/profiling.md +0 -0
  62. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/settings.md +0 -0
  63. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/testing.md +0 -0
  64. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/img/pfx.png +0 -0
  65. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/img/pfx.svg +0 -0
  66. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/make_messages +0 -0
  67. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/__init__.py +0 -0
  68. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/__init__.py +0 -0
  69. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/__init__.py +0 -0
  70. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/parameters.py +0 -0
  71. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/schema.py +0 -0
  72. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/tags.py +0 -0
  73. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apps.py +0 -0
  74. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/__init__.py +0 -0
  75. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/rest.py +0 -0
  76. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/default_settings.py +0 -0
  77. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/exceptions.py +0 -0
  78. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/fields.py +0 -0
  79. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/http/__init__.py +0 -0
  80. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/http/json_response.py +0 -0
  81. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  82. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/__init__.py +0 -0
  83. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/__init__.py +0 -0
  84. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  85. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/profile.py +0 -0
  86. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/__init__.py +0 -0
  87. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/authentication.py +0 -0
  88. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/locale.py +0 -0
  89. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/profiling.py +0 -0
  90. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  91. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  92. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  93. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/__init__.py +0 -0
  94. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/__init__.py +0 -0
  95. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/cache_mixins.py +0 -0
  96. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/login_ban.py +0 -0
  97. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/not_null_fields.py +0 -0
  98. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
  99. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_models.py +0 -0
  100. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  101. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/__init__.py +0 -0
  102. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/json.py +0 -0
  103. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/settings.py +0 -0
  104. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/shortcuts.py +0 -0
  105. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/__init__.py +0 -0
  106. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/s3_storage.py +0 -0
  107. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  108. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  109. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  110. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  111. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  112. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  113. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/test.py +0 -0
  114. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/urls.py +0 -0
  115. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/__init__.py +0 -0
  116. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/fields.py +0 -0
  117. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/filters_views.py +0 -0
  118. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/locale_views.py +0 -0
  119. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  120. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  121. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/groups.py +0 -0
  122. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  123. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  124. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  125. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  126. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  127. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  128. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  129. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  130. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  131. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset.py +0 -0
  132. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  133. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  134. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  135. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  136. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  137. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/rest_views.py +0 -0
  138. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/settings/__init__.py +0 -0
  139. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/settings/dev.py +0 -0
  140. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pyproject.toml +0 -0
  141. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/requirements.txt +0 -0
  142. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/serve-doc +0 -0
  143. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/setup.cfg +0 -0
  144. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/setup.py +0 -0
  145. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/__init__.py +0 -0
  146. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  147. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/migrations/__init__.py +0 -0
  148. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/__init__.py +0 -0
  149. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/ci.py +0 -0
  150. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/common.py +0 -0
  151. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev.py +0 -0
  152. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev_custom_example.py +0 -0
  153. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev_default.py +0 -0
  154. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/__init__.py +0 -0
  155. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/basic_api_errors.py +0 -0
  156. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/basic_api_test.py +0 -0
  157. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_api_doc.py +0 -0
  158. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_api_doc_search.py +0 -0
  159. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_auth_api.py +0 -0
  160. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_body_mixin.py +0 -0
  161. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_cache.py +0 -0
  162. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_fields.py +0 -0
  163. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_filters.py +0 -0
  164. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_locale_api.py +0 -0
  165. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_perm_tests.py +0 -0
  166. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_permissions.py +0 -0
  167. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_perms_api.py +0 -0
  168. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_profiling_middleware.py +0 -0
  169. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_settings.py +0 -0
  170. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_shortcuts.py +0 -0
  171. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_timezone_middleware.py +0 -0
  172. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_tools.py +0 -0
  173. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_user_queryset.py +0 -0
  174. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_view_decorators.py +0 -0
  175. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_view_fields.py +0 -0
  176. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/urls.py +0 -0
  177. {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/views.py +0 -0
@@ -33,19 +33,22 @@ quality check:
33
33
  - isort . -c
34
34
  - ./make_messages
35
35
  - git diff --exit-code # exit if messages changed
36
- - python manage.py makemigrations --check --dry-run --setting='pfx.settings.dev'
36
+ - python manage.py makemigrations --check --dry-run
37
+ - python manage.py makemigrations tests_base_user --check --dry-run
38
+ - python manage.py makemigrations tests_custom_user --check --dry-run
37
39
 
38
40
  test:
39
41
  variables:
40
42
  POSTGRES_DB: ci
41
43
  POSTGRES_USER: postgres
42
44
  POSTGRES_PASSWORD: postgres
43
- DJANGO_SETTINGS_MODULE: 'tests.settings.ci'
44
45
  script:
45
46
  - apt-get update
46
47
  - apt-get install -y gettext
47
48
  - python manage.py compilemessages -i venv
48
- - coverage run --source='.' manage.py test
49
+ - coverage run -a --source='.' manage.py test
50
+ - coverage run -a --source='.' manage.py test tests_base_user
51
+ - coverage run -a --source='.' manage.py test tests_custom_user
49
52
  - coverage report
50
53
  - coverage xml
51
54
  - coverage html
@@ -20,3 +20,10 @@ repos:
20
20
  entry: isort
21
21
  language: system
22
22
  types: [python]
23
+ - repo: local
24
+ hooks:
25
+ - id: make-messages
26
+ name: make messages
27
+ entry: ./make_messages
28
+ language: system
29
+ types: [python]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev68
3
+ Version: 1.4.dev70
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.dev68
3
+ Version: 1.4.dev70
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
@@ -144,4 +144,33 @@ tests/tests/test_timezone_middleware.py
144
144
  tests/tests/test_tools.py
145
145
  tests/tests/test_user_queryset.py
146
146
  tests/tests/test_view_decorators.py
147
- tests/tests/test_view_fields.py
147
+ tests/tests/test_view_fields.py
148
+ tests_base_user/__init__.py
149
+ tests_base_user/urls.py
150
+ tests_base_user/views.py
151
+ tests_base_user/migrations/0001_initial.py
152
+ tests_base_user/migrations/__init__.py
153
+ tests_base_user/settings/__init__.py
154
+ tests_base_user/settings/ci.py
155
+ tests_base_user/settings/common.py
156
+ tests_base_user/settings/dev.py
157
+ tests_base_user/settings/dev_custom_example.py
158
+ tests_base_user/settings/dev_default.py
159
+ tests_base_user/tests/__init__.py
160
+ tests_base_user/tests/test_api.py
161
+ tests_base_user/tests/test_auth_api.py
162
+ tests_custom_user/__init__.py
163
+ tests_custom_user/models.py
164
+ tests_custom_user/urls.py
165
+ tests_custom_user/views.py
166
+ tests_custom_user/migrations/0001_initial.py
167
+ tests_custom_user/migrations/__init__.py
168
+ tests_custom_user/settings/__init__.py
169
+ tests_custom_user/settings/ci.py
170
+ tests_custom_user/settings/common.py
171
+ tests_custom_user/settings/dev.py
172
+ tests_custom_user/settings/dev_custom_example.py
173
+ tests_custom_user/settings/dev_default.py
174
+ tests_custom_user/tests/__init__.py
175
+ tests_custom_user/tests/test_api.py
176
+ tests_custom_user/tests/test_auth_api.py
@@ -18,11 +18,20 @@ writer.MIGRATION_HEADER_TEMPLATE = """\
18
18
 
19
19
  def main():
20
20
  """Run administrative tasks."""
21
- cmd = len(sys.argv) > 1 and sys.argv[1]
22
- os.environ.setdefault(
23
- "DJANGO_SETTINGS_MODULE",
24
- cmd in ('test', 'makemigrations') and
25
- "tests.settings.dev" or "pfx.settings.dev")
21
+ mode = os.environ.get('CI', '').lower() == 'true' and 'ci' or 'dev'
22
+ argv = [a for a in sys.argv if not a.startswith('--')]
23
+ options = [a for a in sys.argv if a.startswith('--')]
24
+ settings = f"pfx.settings.dev"
25
+ cmd = len(argv) > 1 and argv[1]
26
+ if cmd == 'test':
27
+ app = len(argv) > 2 and argv[2] or 'tests'
28
+ if len(argv) <= 2:
29
+ argv.append('tests')
30
+ settings = f"{app.split('.')[0]}.settings.{mode}"
31
+ elif cmd == 'makemigrations':
32
+ app = len(argv) > 2 and argv[2] or 'pfx'
33
+ settings = f"{app}.settings.{app == 'pfx' and 'dev' or 'common'}"
34
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings)
26
35
  try:
27
36
  from django.core.management import execute_from_command_line
28
37
  except ImportError as exc:
@@ -31,7 +40,7 @@ def main():
31
40
  "available on your PYTHONPATH environment variable? Did you "
32
41
  "forget to activate a virtual environment?"
33
42
  ) from exc
34
- execute_from_command_line(sys.argv)
43
+ execute_from_command_line([*argv, *options])
35
44
 
36
45
 
37
46
  if __name__ == '__main__':
@@ -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 14:22+0100\n"
10
+ "POT-Creation-Date: 2025-01-21 18:35+0100\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -59,6 +59,14 @@ msgstr ""
59
59
  "Format non valide, il peut s’agir d’un nombre en heures, « 1:05 », « :05 », "
60
60
  "« 1h 5m », « 1.5h » ou « 30m »."
61
61
 
62
+ #: models/abstract_pfx_base_user.py:35
63
+ msgid "user"
64
+ msgstr ""
65
+
66
+ #: models/abstract_pfx_base_user.py:36
67
+ msgid "users"
68
+ msgstr ""
69
+
62
70
  #: models/login_ban.py:45
63
71
  msgid "Username"
64
72
  msgstr "Nom d’utilisateur"
@@ -95,7 +103,7 @@ msgstr "Compte HOTP"
95
103
  msgid "HOTP expiry"
96
104
  msgstr "Expiration HOTP"
97
105
 
98
- #: models/otp_user_mixin.py:29 views/authentication_views.py:496
106
+ #: models/otp_user_mixin.py:29 views/authentication_views.py:491
99
107
  msgid "OTP enabled"
100
108
  msgstr "OTP activé"
101
109
 
@@ -209,7 +217,7 @@ msgstr ""
209
217
  msgid "Successful login"
210
218
  msgstr "Connexion réussie"
211
219
 
212
- #: views/authentication_views.py:243 views/authentication_views.py:413
220
+ #: views/authentication_views.py:243 views/authentication_views.py:408
213
221
  msgid "password updated successfully"
214
222
  msgstr "le mot de passe a été mis à jour avec succès"
215
223
 
@@ -217,31 +225,31 @@ msgstr "le mot de passe a été mis à jour avec succès"
217
225
  msgid "Incorrect password"
218
226
  msgstr "Mot de passe incorrect"
219
227
 
220
- #: views/authentication_views.py:251 views/authentication_views.py:422
228
+ #: views/authentication_views.py:251 views/authentication_views.py:417
221
229
  msgid "Empty password is not allowed"
222
230
  msgstr "Un mot de passe vide n’est pas autorisé"
223
231
 
224
- #: views/authentication_views.py:347
232
+ #: views/authentication_views.py:342
225
233
  msgid "User and token are valid"
226
234
  msgstr "L'utilisateur et le token sont valides"
227
235
 
228
- #: views/authentication_views.py:349
236
+ #: views/authentication_views.py:344
229
237
  msgid "User or token is invalid"
230
238
  msgstr "L'utilisateur ou le token est invalide"
231
239
 
232
- #: views/authentication_views.py:456
240
+ #: views/authentication_views.py:451
233
241
  msgid "OTP is already enabled"
234
242
  msgstr "OTP est déjà activé"
235
243
 
236
- #: views/authentication_views.py:497 views/authentication_views.py:533
244
+ #: views/authentication_views.py:492 views/authentication_views.py:528
237
245
  msgid "Invalid code"
238
246
  msgstr "Code invalide"
239
247
 
240
- #: views/authentication_views.py:532
248
+ #: views/authentication_views.py:527
241
249
  msgid "OTP disabled"
242
250
  msgstr "OTP désactivé"
243
251
 
244
- #: views/authentication_views.py:792
252
+ #: views/authentication_views.py:787
245
253
  msgid ""
246
254
  "If the email address you entered is correct, you will receive an email from "
247
255
  "us with instructions to reset your password."
@@ -250,7 +258,7 @@ msgstr ""
250
258
  "un courrier électronique de notre part contenant des instructions pour "
251
259
  "réinitialiser votre mot de passe."
252
260
 
253
- #: views/authentication_views.py:866
261
+ #: views/authentication_views.py:861
254
262
  msgid "A new authentication code has been sent by email."
255
263
  msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
256
264
 
@@ -1,4 +1,5 @@
1
1
  from django.contrib.auth.models import AbstractBaseUser, AbstractUser
2
+ from django.utils.translation import gettext_lazy as _
2
3
 
3
4
  from .pfx_models import PFXModelMixin
4
5
 
@@ -9,6 +10,13 @@ class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
9
10
  class Meta:
10
11
  abstract = True
11
12
 
13
+ def auth_json_repr(self):
14
+ return self.json_repr()
15
+
16
+ @classmethod
17
+ def auth_json_repr_schema(cls):
18
+ return cls.json_repr_schema()
19
+
12
20
  def get_user_jwt_signature_key(self):
13
21
  """
14
22
  Return a user secret to sign JWT token.
@@ -24,4 +32,6 @@ class AbstractPFXUser(AbstractUser, AbstractPFXBaseUser):
24
32
  """The base abstract user for PFX with permissions mixin."""
25
33
 
26
34
  class Meta:
35
+ verbose_name = _("user")
36
+ verbose_name_plural = _("users")
27
37
  abstract = True
@@ -1,4 +1,4 @@
1
- from django.contrib.auth.models import AbstractUser
1
+ # from django.contrib.auth.models import AbstractUser
2
2
 
3
3
  from .abstract_pfx_base_user import AbstractPFXUser
4
4
 
@@ -7,5 +7,5 @@ class PFXUser(AbstractPFXUser):
7
7
  """The Django User with PFX mixins.
8
8
  """
9
9
 
10
- class Meta(AbstractUser.Meta):
10
+ class Meta(AbstractPFXUser.Meta):
11
11
  swappable = "AUTH_USER_MODEL"
@@ -20,7 +20,7 @@ from django.views.decorators.debug import sensitive_post_parameters
20
20
 
21
21
  import jwt
22
22
 
23
- from pfx.pfxcore.apidoc import ModelSchema, Schema, Tag
23
+ from pfx.pfxcore.apidoc import Schema, Tag
24
24
  from pfx.pfxcore.decorator import rest_api, rest_doc, rest_view
25
25
  from pfx.pfxcore.exceptions import (
26
26
  AuthenticationError,
@@ -286,12 +286,7 @@ class AuthenticationView(
286
286
  Can be overridden to customize result.
287
287
 
288
288
  :param user: The user"""
289
- info = {
290
- 'username': user.get_username(),
291
- 'first_name': user.first_name,
292
- 'last_name': user.last_name,
293
- 'email': user.email
294
- }
289
+ info = user.auth_json_repr()
295
290
  if isinstance(user, OtpUserMixin):
296
291
  info.update(is_otp=user.is_otp)
297
292
  return info
@@ -301,8 +296,8 @@ class AuthenticationView(
301
296
  """Get user representation schema.
302
297
 
303
298
  Can be overridden to customize result."""
304
- return ModelSchema(UserModel, cls._process_fields([
305
- 'username', 'first_name', 'last_name', 'email']))
299
+ return Schema(
300
+ 'auth_user', "User", **UserModel.auth_json_repr_schema())
306
301
 
307
302
  @method_decorator(sensitive_post_parameters())
308
303
  @method_decorator(never_cache)
@@ -1,4 +1,4 @@
1
- # Generated by Django 4.2.17 on 2025-01-21 04:24
1
+ # Generated by Django 4.2.17 on 2025-01-21 08:32
2
2
  # flake8: noqa
3
3
 
4
4
  import django.contrib.auth.models
@@ -56,19 +56,6 @@ class Migration(migrations.Migration):
56
56
  },
57
57
  bases=(pfx.pfxcore.models.cache_mixins.CacheDependsMixin, pfx.pfxcore.models.pfx_models.PFXModelMixin, models.Model),
58
58
  ),
59
- migrations.CreateModel(
60
- name='TestModel',
61
- fields=[
62
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
63
- ('name', models.CharField(max_length=30, verbose_name='Name')),
64
- ],
65
- options={
66
- 'verbose_name': 'TestModel',
67
- 'verbose_name_plural': 'TestModels',
68
- 'ordering': ['name', 'pk'],
69
- },
70
- bases=(pfx.pfxcore.models.pfx_models.JSONReprMixin, models.Model),
71
- ),
72
59
  migrations.CreateModel(
73
60
  name='Book',
74
61
  fields=[
@@ -166,16 +166,3 @@ class Book(CacheDependsMixin, PFXModelMixin, models.Model):
166
166
  type: string
167
167
  """
168
168
  return super().json_repr(author_name=str(self.author), **values)
169
-
170
-
171
- class TestModel(JSONReprMixin, models.Model):
172
-
173
- name = models.CharField("Name", max_length=30)
174
-
175
- class Meta:
176
- verbose_name = "TestModel"
177
- verbose_name_plural = "TestModels"
178
- ordering = ['name', 'pk']
179
-
180
- def __str__(self):
181
- return self.name
@@ -1,3 +1,4 @@
1
+ from django.db import connection, models
1
2
  from django.http import HttpResponse
2
3
  from django.test import TestCase
3
4
  from django.test.utils import override_settings
@@ -6,9 +7,22 @@ from django.urls import include, path
6
7
  from pfx.pfxcore import register_views
7
8
  from pfx.pfxcore.decorator import rest_api, rest_view
8
9
  from pfx.pfxcore.http import JsonResponse
10
+ from pfx.pfxcore.models import JSONReprMixin
9
11
  from pfx.pfxcore.test import APIClient, TestAssertMixin
10
12
  from pfx.pfxcore.views import RestView
11
- from tests.models import TestModel, User
13
+ from tests.models import User
14
+
15
+
16
+ class TestModel(JSONReprMixin, models.Model):
17
+ name = models.CharField("Name", max_length=30)
18
+
19
+ class Meta:
20
+ verbose_name = "TestModel"
21
+ verbose_name_plural = "TestModels"
22
+ ordering = ['name', 'pk']
23
+
24
+ def __str__(self):
25
+ return self.name
12
26
 
13
27
 
14
28
  @rest_view("/test")
@@ -56,8 +70,15 @@ class TestApiClient(TestAssertMixin, TestCase):
56
70
  def setUp(self):
57
71
  self.client = APIClient(default_locale='en')
58
72
 
73
+ # @classmethod
74
+ # def setUpClass(cls):
75
+
76
+ # super(TestApiClient, cls).setUpClass()
77
+
59
78
  @classmethod
60
79
  def setUpTestData(cls):
80
+ with connection.schema_editor() as schema_editor:
81
+ schema_editor.create_model(TestModel)
61
82
  cls.user = User.objects.create_user(
62
83
  username='jrr.tolkien',
63
84
  email="jrr.tolkien@oxford.com",
File without changes
@@ -0,0 +1,13 @@
1
+ # Generated by Django 4.2.17 on 2025-01-21 09:43
2
+ # flake8: noqa
3
+
4
+ from django.conf import settings
5
+ from django.db import migrations
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ initial = True
10
+
11
+ dependencies = [
12
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+ ]
@@ -0,0 +1,18 @@
1
+ from .common import * # noqa
2
+
3
+ DATABASES = {
4
+ 'default': {
5
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
6
+ 'NAME': 'ci',
7
+ 'USER': 'postgres',
8
+ 'PASSWORD': 'postgres',
9
+ 'HOST': 'postgres',
10
+ 'PORT': '5432',
11
+ }
12
+ }
13
+
14
+ TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
15
+ TEST_OUTPUT_FILE_NAME = 'testreport.xml'
16
+ TEST_MODE = True
17
+ # TEST_OUTPUT_VERBOSE = 1
18
+ # TEST_OUTPUT_DESCRIPTIONS = False
@@ -0,0 +1,80 @@
1
+ import os
2
+
3
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
4
+
5
+ SECRET_KEY = 'fake-key'
6
+ INSTALLED_APPS = [
7
+ 'django.contrib.auth',
8
+ 'django.contrib.contenttypes',
9
+ 'django.contrib.postgres',
10
+ 'pfx.pfxcore',
11
+ 'tests_base_user',
12
+ ]
13
+
14
+ MIDDLEWARE = [
15
+ 'pfx.pfxcore.middleware.LocaleMiddleware',
16
+ 'django.middleware.security.SecurityMiddleware',
17
+ 'django.middleware.common.CommonMiddleware',
18
+ 'pfx.pfxcore.middleware.AuthenticationMiddleware',
19
+ 'pfx.pfxcore.middleware.CookieAuthenticationMiddleware',
20
+ ]
21
+
22
+ USE_I18N = True
23
+ USE_L10N = True
24
+ LANGUAGE_CODE = 'en'
25
+ LANGUAGES = [
26
+ ('en', 'English'),
27
+ ('fr', 'French')]
28
+ LOCALE_PATHS = [
29
+ os.path.join(BASE_DIR, "tests_base_user/locale")]
30
+
31
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
32
+
33
+ AUTH_USER_MODEL = 'pfxcore.PFXUser'
34
+
35
+ PFX_SECRET_KEY = "fake-secret-key"
36
+ PFX_COOKIE_DOMAIN = None
37
+
38
+ PFX_MAX_LIST_RESULT_SIZE = 0
39
+
40
+ ROOT_URLCONF = 'tests_base_user.urls'
41
+ APPEND_SLASH = False
42
+
43
+ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
44
+ PFX_RESET_PASSWORD_URL = (
45
+ 'http://localhost:8000/test?token={token}&uidb64={uidb64}')
46
+ PFX_SITE_NAME = 'Books Demo'
47
+
48
+ # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
49
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
50
+
51
+ TEMPLATES = [
52
+ {
53
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
54
+ 'DIRS': [],
55
+ 'APP_DIRS': True,
56
+ }
57
+ ]
58
+
59
+ LOGGING = {
60
+ 'version': 1,
61
+ 'disable_existing_logger': False,
62
+ 'formatters': {
63
+ 'console': {
64
+ 'format': "\n%(name)-25s %(levelname)-8s %(message)s",
65
+ },
66
+ },
67
+ 'handlers': {
68
+ 'console': {
69
+ 'class': 'logging.StreamHandler',
70
+ 'formatter': 'console',
71
+ },
72
+ },
73
+ 'loggers': {
74
+ '': {
75
+ 'handlers': ['console'],
76
+ 'level': 'ERROR',
77
+ 'propagate': True,
78
+ },
79
+ },
80
+ }
@@ -0,0 +1,13 @@
1
+ """
2
+ Development settings
3
+
4
+ Load .dev_custom if it exists for personal settings (ignored by git).
5
+ Use .dev_default directly if no.
6
+
7
+ Use: `cp dev_custom_example.py dev_custom.py to create it.`
8
+ """
9
+
10
+ try:
11
+ from .dev_custom import * # noqa
12
+ except ImportError:
13
+ from .dev_default import * # noqa
@@ -0,0 +1,28 @@
1
+ """
2
+ Custom development settings example.
3
+
4
+ To use custom settting please copy this file:
5
+ `cp dev_example.py dev_custom.py to create it.`
6
+ """
7
+
8
+ from .dev_default import * # noqa
9
+
10
+ # SECRET_KEY = 'fake-key'
11
+ # INSTALLED_APPS = [
12
+ # 'django.contrib.contenttypes',
13
+ # 'tests',
14
+ # ]
15
+ #
16
+ # DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
17
+ #
18
+ # DATABASES = {
19
+ # 'default': {
20
+ # 'ENGINE': 'django.db.backends.postgresql_psycopg2',
21
+ # 'NAME': 'test-pfx',
22
+ # 'USER': 'django',
23
+ # 'PASSWORD': 'django',
24
+ # 'HOST': 'localhost',
25
+ # 'PORT': '5432',
26
+ # }
27
+ # }
28
+ # ROOT_URLCONF = 'tests.urls'
@@ -0,0 +1,12 @@
1
+ from .common import * # noqa
2
+
3
+ DATABASES = {
4
+ 'default': {
5
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
6
+ 'NAME': 'test-pfx-base-user',
7
+ 'USER': 'django',
8
+ 'PASSWORD': 'django',
9
+ 'HOST': 'localhost',
10
+ 'PORT': '5432',
11
+ }
12
+ }
@@ -0,0 +1,2 @@
1
+ from .test_api import TestApi
2
+ from .test_auth_api import AuthAPITest
@@ -0,0 +1,32 @@
1
+ from django.test import TestCase
2
+
3
+ from pfx.pfxcore.models import PFXUser
4
+ from pfx.pfxcore.shortcuts import permissions
5
+ from pfx.pfxcore.test import APIClient, TestAssertMixin
6
+
7
+
8
+ class TestApi(TestAssertMixin, TestCase):
9
+
10
+ def setUp(self):
11
+ self.client = APIClient(default_locale='en')
12
+
13
+ @classmethod
14
+ def setUpTestData(cls):
15
+ cls.user = PFXUser.objects.create_user(
16
+ username='user',
17
+ password='test',
18
+ first_name='Test',
19
+ last_name='User',
20
+ )
21
+
22
+ def test_get_user(self):
23
+ self.client.login(username='user')
24
+
25
+ response = self.client.get(f'/api/users/{self.user.pk}')
26
+ self.assertRC(response, 403)
27
+
28
+ self.user.user_permissions.add(*permissions('pfxcore.view_pfxuser'))
29
+
30
+ response = self.client.get(f'/api/users/{self.user.pk}')
31
+ self.assertRC(response, 200)
32
+ self.assertJE(response, 'username', 'user')
@@ -0,0 +1,59 @@
1
+ import logging
2
+ from datetime import datetime, timedelta
3
+
4
+ from django.conf import settings
5
+ from django.test import TransactionTestCase, override_settings
6
+
7
+ import jwt
8
+ from freezegun import freeze_time
9
+
10
+ from pfx.pfxcore.models import PFXUser
11
+ from pfx.pfxcore.test import APIClient, TestAssertMixin
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class AuthAPITest(TestAssertMixin, TransactionTestCase):
17
+
18
+ def setUp(self):
19
+ self.client = APIClient(default_locale='en')
20
+ self.cookie_client = APIClient(default_locale='en', with_cookie=True)
21
+ self.user1 = PFXUser.objects.create_user(
22
+ username='jrr.tolkien',
23
+ email="jrr.tolkien@oxford.com",
24
+ password='RIGHT PASSWORD',
25
+ first_name='John Ronald Reuel',
26
+ last_name='Tolkien',
27
+ )
28
+
29
+ def test_invalid_login(self):
30
+ response = self.client.post(
31
+ '/api/auth/login', {
32
+ 'username': 'jrr.tolkien',
33
+ 'password': 'WRONG PASSWORD'})
34
+ self.assertRC(response, 422)
35
+
36
+ def test_emtpy_login(self):
37
+ response = self.client.post(
38
+ '/api/auth/login', {})
39
+ self.assertRC(response, 422)
40
+
41
+ @override_settings(PFX_TOKEN_SHORT_VALIDITY={'minutes': 30})
42
+ def test_valid_login(self):
43
+ with freeze_time("2023-05-01 08:00:00"):
44
+ response = self.client.post(
45
+ '/api/auth/login', {
46
+ 'username': 'jrr.tolkien',
47
+ 'password': 'RIGHT PASSWORD'})
48
+
49
+ self.assertRC(response, 200)
50
+ token = self.get_val(response, 'token')
51
+ headers = jwt.get_unverified_header(token)
52
+ self.assertEqual(headers['pfx_user_pk'], self.user1.pk)
53
+ decoded = jwt.decode(
54
+ token, self.user1.password + settings.PFX_SECRET_KEY,
55
+ algorithms="HS256")
56
+ self.assertTrue(
57
+ datetime.utcnow() + timedelta(minutes=25) <
58
+ datetime.utcfromtimestamp(decoded['exp'])
59
+ < datetime.utcnow() + timedelta(minutes=35))
@@ -0,0 +1,13 @@
1
+ from django.urls import include, path
2
+
3
+ from pfx.pfxcore import register_views
4
+
5
+ from . import views
6
+
7
+ handler404 = 'pfx.pfxcore.views.resource_not_found'
8
+
9
+ urlpatterns = [
10
+ path('api/', include(register_views(
11
+ views.UserRestView))),
12
+ path('api/', include('pfx.pfxcore.urls'))
13
+ ]