django-pfx 1.4.dev104__tar.gz → 1.4.dev106__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 (192) hide show
  1. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/PKG-INFO +2 -1
  2. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/django_pfx.egg-info/PKG-INFO +2 -1
  3. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/django_pfx.egg-info/SOURCES.txt +5 -1
  4. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/django_pfx.egg-info/requires.txt +1 -0
  5. django_pfx-1.4.dev106/pfx/pfxcore/fields/__init__.py +3 -0
  6. django_pfx-1.4.dev106/pfx/pfxcore/fields/media_field.py +60 -0
  7. django_pfx-1.4.dev104/pfx/pfxcore/fields.py → django_pfx-1.4.dev106/pfx/pfxcore/fields/minutes_duration_field.py +0 -55
  8. django_pfx-1.4.dev106/pfx/pfxcore/fields/nh3_field.py +83 -0
  9. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +3 -3
  10. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/requirements.txt +1 -0
  11. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/setup.cfg +1 -0
  12. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/__init__.py +1 -0
  13. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_fields_minutes_duration.py +1 -1
  14. django_pfx-1.4.dev106/tests/tests/test_fields_nh3.py +38 -0
  15. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/.gitignore +0 -0
  16. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/.gitlab-ci.yml +0 -0
  17. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/.pre-commit-config.yaml +0 -0
  18. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/LICENSE +0 -0
  19. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/MANIFEST.in +0 -0
  20. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/README.md +0 -0
  21. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/django_pfx.egg-info/dependency_links.txt +0 -0
  22. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/django_pfx.egg-info/top_level.txt +0 -0
  23. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/Makefile +0 -0
  24. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/conf.py +0 -0
  25. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/index.rst +0 -0
  26. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/api.views.rst +0 -0
  27. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/authentication.md +0 -0
  28. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/decorator.md +0 -0
  29. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/generate_openapi.md +0 -0
  30. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/getting_started.md +0 -0
  31. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/internationalisation.md +0 -0
  32. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/model.md +0 -0
  33. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/pfx_views.md +0 -0
  34. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/profiling.md +0 -0
  35. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/settings.md +0 -0
  36. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/doc/source/testing.md +0 -0
  37. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/img/pfx.png +0 -0
  38. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/img/pfx.svg +0 -0
  39. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/make_messages +0 -0
  40. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/manage.py +0 -0
  41. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/__init__.py +0 -0
  42. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/__init__.py +0 -0
  43. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/apidoc/__init__.py +0 -0
  44. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/apidoc/parameters.py +0 -0
  45. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/apidoc/schema.py +0 -0
  46. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/apidoc/tags.py +0 -0
  47. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/apps.py +0 -0
  48. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/decorator/__init__.py +0 -0
  49. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/decorator/rest.py +0 -0
  50. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/default_settings.py +0 -0
  51. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/exceptions.py +0 -0
  52. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/http/__init__.py +0 -0
  53. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/http/json_response.py +0 -0
  54. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  55. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/management/__init__.py +0 -0
  56. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/management/commands/__init__.py +0 -0
  57. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  58. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/management/commands/profile.py +0 -0
  59. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/middleware/__init__.py +0 -0
  60. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/middleware/authentication.py +0 -0
  61. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/middleware/locale.py +0 -0
  62. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/middleware/profiling.py +0 -0
  63. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  64. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  65. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  66. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/__init__.py +0 -0
  67. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
  68. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
  69. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/__init__.py +0 -0
  70. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
  71. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/cache_mixins.py +0 -0
  72. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/login_ban.py +0 -0
  73. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/not_null_fields.py +0 -0
  74. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/ordered_model_mixin.py +0 -0
  75. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
  76. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/pfx_models.py +0 -0
  77. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/pfx_user.py +0 -0
  78. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  79. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/serializers/__init__.py +0 -0
  80. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/serializers/json.py +0 -0
  81. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/settings.py +0 -0
  82. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/shortcuts.py +0 -0
  83. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/storage/__init__.py +0 -0
  84. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/storage/exceptions.py +0 -0
  85. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/storage/local_storage.py +0 -0
  86. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/storage/s3_storage.py +0 -0
  87. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  88. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  89. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  90. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  91. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  92. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  93. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/test.py +0 -0
  94. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/urls.py +0 -0
  95. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/__init__.py +0 -0
  96. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/authentication_views.py +0 -0
  97. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/fields.py +0 -0
  98. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/filters_views.py +0 -0
  99. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/locale_views.py +0 -0
  100. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
  101. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
  102. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  103. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  104. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/groups.py +0 -0
  105. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  106. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  107. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  108. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  109. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  110. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  111. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  112. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  113. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  114. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset.py +0 -0
  115. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  116. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  117. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  118. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  119. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  120. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/pfxcore/views/rest_views.py +0 -0
  121. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/settings/__init__.py +0 -0
  122. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pfx/settings/dev.py +0 -0
  123. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/pyproject.toml +0 -0
  124. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/serve-doc +0 -0
  125. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/setup.py +0 -0
  126. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/__init__.py +0 -0
  127. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/apps.py +0 -0
  128. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  129. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/migrations/0001_initial.py +0 -0
  130. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/migrations/__init__.py +0 -0
  131. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/models.py +0 -0
  132. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/__init__.py +0 -0
  133. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/ci.py +0 -0
  134. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/common.py +0 -0
  135. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/dev.py +0 -0
  136. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/dev_custom_example.py +0 -0
  137. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/settings/dev_default.py +0 -0
  138. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/basic_api_errors.py +0 -0
  139. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/basic_api_test.py +0 -0
  140. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_api_doc.py +0 -0
  141. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_api_doc_search.py +0 -0
  142. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_auth_api.py +0 -0
  143. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_body_mixin.py +0 -0
  144. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_cache.py +0 -0
  145. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_client.py +0 -0
  146. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_fields_choices.py +0 -0
  147. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_filters.py +0 -0
  148. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_locale_api.py +0 -0
  149. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
  150. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_perm_tests.py +0 -0
  151. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_permissions.py +0 -0
  152. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_perms_api.py +0 -0
  153. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_post_migrate_groups_update.py +0 -0
  154. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_profiling_middleware.py +0 -0
  155. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_settings.py +0 -0
  156. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_shortcuts.py +0 -0
  157. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_timezone_middleware.py +0 -0
  158. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_tools.py +0 -0
  159. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_user_queryset.py +0 -0
  160. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_view_decorators.py +0 -0
  161. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/tests/test_view_fields.py +0 -0
  162. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/urls.py +0 -0
  163. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests/views.py +0 -0
  164. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/__init__.py +0 -0
  165. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/migrations/0001_initial.py +0 -0
  166. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/migrations/__init__.py +0 -0
  167. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/__init__.py +0 -0
  168. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/ci.py +0 -0
  169. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/common.py +0 -0
  170. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/dev.py +0 -0
  171. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/dev_custom_example.py +0 -0
  172. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/settings/dev_default.py +0 -0
  173. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/tests/__init__.py +0 -0
  174. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/tests/test_api.py +0 -0
  175. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/tests/test_auth_api.py +0 -0
  176. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/urls.py +0 -0
  177. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_base_user/views.py +0 -0
  178. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/__init__.py +0 -0
  179. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/migrations/0001_initial.py +0 -0
  180. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/migrations/__init__.py +0 -0
  181. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/models.py +0 -0
  182. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/__init__.py +0 -0
  183. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/ci.py +0 -0
  184. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/common.py +0 -0
  185. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/dev.py +0 -0
  186. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/dev_custom_example.py +0 -0
  187. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/settings/dev_default.py +0 -0
  188. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/tests/__init__.py +0 -0
  189. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/tests/test_api.py +0 -0
  190. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/tests/test_auth_api.py +0 -0
  191. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/tests_custom_user/urls.py +0 -0
  192. {django_pfx-1.4.dev104 → django_pfx-1.4.dev106}/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.dev104
3
+ Version: 1.4.dev106
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
@@ -34,6 +34,7 @@ Requires-Dist: apispec
34
34
  Requires-Dist: pyyaml
35
35
  Requires-Dist: pytz
36
36
  Requires-Dist: dill
37
+ Requires-Dist: nh3
37
38
  Provides-Extra: otp
38
39
  Requires-Dist: pyotp; extra == "otp"
39
40
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev104
3
+ Version: 1.4.dev106
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
@@ -34,6 +34,7 @@ Requires-Dist: apispec
34
34
  Requires-Dist: pyyaml
35
35
  Requires-Dist: pytz
36
36
  Requires-Dist: dill
37
+ Requires-Dist: nh3
37
38
  Provides-Extra: otp
38
39
  Requires-Dist: pyotp; extra == "otp"
39
40
 
@@ -37,7 +37,6 @@ pfx/pfxcore/__init__.py
37
37
  pfx/pfxcore/apps.py
38
38
  pfx/pfxcore/default_settings.py
39
39
  pfx/pfxcore/exceptions.py
40
- pfx/pfxcore/fields.py
41
40
  pfx/pfxcore/settings.py
42
41
  pfx/pfxcore/shortcuts.py
43
42
  pfx/pfxcore/test.py
@@ -48,6 +47,10 @@ pfx/pfxcore/apidoc/schema.py
48
47
  pfx/pfxcore/apidoc/tags.py
49
48
  pfx/pfxcore/decorator/__init__.py
50
49
  pfx/pfxcore/decorator/rest.py
50
+ pfx/pfxcore/fields/__init__.py
51
+ pfx/pfxcore/fields/media_field.py
52
+ pfx/pfxcore/fields/minutes_duration_field.py
53
+ pfx/pfxcore/fields/nh3_field.py
51
54
  pfx/pfxcore/http/__init__.py
52
55
  pfx/pfxcore/http/json_response.py
53
56
  pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo
@@ -141,6 +144,7 @@ tests/tests/test_cache.py
141
144
  tests/tests/test_client.py
142
145
  tests/tests/test_fields_choices.py
143
146
  tests/tests/test_fields_minutes_duration.py
147
+ tests/tests/test_fields_nh3.py
144
148
  tests/tests/test_filters.py
145
149
  tests/tests/test_locale_api.py
146
150
  tests/tests/test_ordered_rest_view_mixin.py
@@ -7,6 +7,7 @@ apispec
7
7
  pyyaml
8
8
  pytz
9
9
  dill
10
+ nh3
10
11
 
11
12
  [otp]
12
13
  pyotp
@@ -0,0 +1,3 @@
1
+ from .media_field import MediaField
2
+ from .minutes_duration_field import MinutesDurationField
3
+ from .nh3_field import NH3Field
@@ -0,0 +1,60 @@
1
+ import logging
2
+ from importlib import import_module
3
+
4
+ from django.db import models
5
+ from django.db.models.signals import post_delete
6
+ from django.dispatch import receiver
7
+
8
+ from pfx.pfxcore.shortcuts import settings
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def get_storage_class(class_path):
14
+ ps = class_path.split('.')
15
+ return getattr(import_module('.'.join(ps[:-1])), ps[-1])()
16
+
17
+
18
+ class MediaField(models.JSONField):
19
+ def __init__(
20
+ self, *args, max_length=255, get_key=None, storage=None,
21
+ auto_delete=False, **kwargs):
22
+ self.get_key = get_key or self.get_default_key
23
+ if not storage and not settings.STORAGE_DEFAULT:
24
+ raise Exception(
25
+ "Missing storage. You have to set a storage "
26
+ "class on the field or define STORAGE_DEFAULT settings.")
27
+ self.storage = storage or get_storage_class(settings.STORAGE_DEFAULT)
28
+ self.auto_delete = auto_delete
29
+ super().__init__(
30
+ *args, max_length=max_length,
31
+ default=kwargs.pop('default', dict),
32
+ blank=kwargs.pop('blank', True),
33
+ **kwargs)
34
+
35
+ @staticmethod
36
+ def get_default_key(obj, filename):
37
+ return f"{type(obj).__name__}/{obj.pk}/{filename}"
38
+
39
+ def to_python(self, value):
40
+ return super().to_python(self.storage.to_python(value))
41
+
42
+ def get_upload_url(self, request, obj, filename):
43
+ key = self.get_key(obj, filename)
44
+ url = self.storage.get_upload_url(request, key)
45
+ return dict(url=url, file=dict(name=filename, key=key))
46
+
47
+ def get_url(self, request, obj):
48
+ return self.storage.get_url(
49
+ request, self.value_from_object(obj)['key'])
50
+
51
+ def upload(self, obj, file, filename, **kwargs):
52
+ key = self.get_key(obj, filename)
53
+ return self.to_python(self.storage.upload(key, file, **kwargs))
54
+
55
+
56
+ @receiver(post_delete)
57
+ def post_delete_media(sender, instance, **kwargs):
58
+ for field in sender._meta.fields:
59
+ if isinstance(field, MediaField) and field.auto_delete:
60
+ field.storage.delete(field.value_from_object(instance))
@@ -1,69 +1,14 @@
1
1
  import logging
2
2
  import re
3
3
  from datetime import timedelta
4
- from importlib import import_module
5
4
 
6
5
  from django.core.exceptions import ValidationError
7
6
  from django.db import models
8
- from django.db.models.signals import post_delete
9
- from django.dispatch import receiver
10
7
  from django.utils.translation import gettext_lazy as _
11
8
 
12
- from pfx.pfxcore.shortcuts import settings
13
-
14
9
  logger = logging.getLogger(__name__)
15
10
 
16
11
 
17
- def get_storage_class(class_path):
18
- ps = class_path.split('.')
19
- return getattr(import_module('.'.join(ps[:-1])), ps[-1])()
20
-
21
-
22
- class MediaField(models.JSONField):
23
- def __init__(
24
- self, *args, max_length=255, get_key=None, storage=None,
25
- auto_delete=False, **kwargs):
26
- self.get_key = get_key or self.get_default_key
27
- if not storage and not settings.STORAGE_DEFAULT:
28
- raise Exception(
29
- "Missing storage. You have to set a storage "
30
- "class on the field or define STORAGE_DEFAULT settings.")
31
- self.storage = storage or get_storage_class(settings.STORAGE_DEFAULT)
32
- self.auto_delete = auto_delete
33
- super().__init__(
34
- *args, max_length=max_length,
35
- default=kwargs.pop('default', dict),
36
- blank=kwargs.pop('blank', True),
37
- **kwargs)
38
-
39
- @staticmethod
40
- def get_default_key(obj, filename):
41
- return f"{type(obj).__name__}/{obj.pk}/{filename}"
42
-
43
- def to_python(self, value):
44
- return super().to_python(self.storage.to_python(value))
45
-
46
- def get_upload_url(self, request, obj, filename):
47
- key = self.get_key(obj, filename)
48
- url = self.storage.get_upload_url(request, key)
49
- return dict(url=url, file=dict(name=filename, key=key))
50
-
51
- def get_url(self, request, obj):
52
- return self.storage.get_url(
53
- request, self.value_from_object(obj)['key'])
54
-
55
- def upload(self, obj, file, filename, **kwargs):
56
- key = self.get_key(obj, filename)
57
- return self.to_python(self.storage.upload(key, file, **kwargs))
58
-
59
-
60
- @receiver(post_delete)
61
- def post_delete_media(sender, instance, **kwargs):
62
- for field in sender._meta.fields:
63
- if isinstance(field, MediaField) and field.auto_delete:
64
- field.storage.delete(field.value_from_object(instance))
65
-
66
-
67
12
  class MinutesDurationField(models.DurationField):
68
13
  RE_FLOAT = re.compile(r'^[0-9]*(\.[0-9]*)?$')
69
14
  RE_HH_MM = re.compile(r'^([0-9]*):([0-5][0-9])?$')
@@ -0,0 +1,83 @@
1
+ from django.conf import settings
2
+ from django.db import models
3
+ from django.utils.safestring import mark_safe
4
+
5
+ import nh3
6
+
7
+
8
+ def get_nh3_default_options():
9
+ nh3_args = {}
10
+ nh3_settings = {
11
+ "NH3_ALLOWED_TAGS": "tags",
12
+ "NH3_ALLOWED_ATTRIBUTES": "attributes",
13
+ "NH3_STRIP_COMMENTS": "strip_comments",
14
+ "NH3_URL_SCHEMES": "url_schemes",
15
+ "NH3_ATTRIBUTE_FILTER": "attribute_filter",
16
+ "NH3_LINK_REL": "link_rel",
17
+ "NH3_GENERIC_ATTRIBUTE_PREFIXES": "generic_attribute_prefixes",
18
+ "NH3_TAG_ATTRIBUTE_VALUES": "tag_attribute_values",
19
+ "NH3_SET_TAG_ATTRIBUTE_VALUES": "set_tag_attribute_values",
20
+ }
21
+
22
+ for setting, kwarg in nh3_settings.items():
23
+ if hasattr(settings, setting):
24
+ attr = getattr(settings, setting)
25
+ nh3_args[kwarg] = attr
26
+
27
+ return nh3_args
28
+
29
+
30
+ class NH3Field(models.TextField):
31
+ def __init__(
32
+ self,
33
+ allowed_tags=None,
34
+ allowed_attributes=None,
35
+ url_schemes=None,
36
+ strip_comments=None,
37
+ attribute_filter=None,
38
+ link_rel=None,
39
+ generic_attribute_prefixes=None,
40
+ tag_attribute_values=None,
41
+ set_tag_attribute_values=None,
42
+ *args,
43
+ **kwargs,
44
+ ):
45
+ super().__init__(*args, **kwargs)
46
+
47
+ self.nh3_kwargs = get_nh3_default_options()
48
+
49
+ if allowed_tags:
50
+ self.nh3_kwargs["tags"] = allowed_tags
51
+ if allowed_attributes:
52
+ self.nh3_kwargs["attributes"] = allowed_attributes
53
+ if url_schemes:
54
+ self.nh3_kwargs["url_schemes"] = url_schemes
55
+ if strip_comments:
56
+ self.nh3_kwargs["strip_comments"] = strip_comments
57
+ if attribute_filter:
58
+ self.nh3_kwargs["attribute_filter"] = attribute_filter
59
+ if link_rel:
60
+ self.nh3_kwargs["link_rel"] = link_rel
61
+ if generic_attribute_prefixes:
62
+ self.nh3_kwargs["generic_attribute_prefixes"] = (
63
+ generic_attribute_prefixes)
64
+ if tag_attribute_values:
65
+ self.nh3_kwargs["tag_attribute_values"] = tag_attribute_values
66
+ if set_tag_attribute_values:
67
+ self.nh3_kwargs["set_tag_attribute_values"] = (
68
+ set_tag_attribute_values)
69
+
70
+ def pre_save(self, model_instance, add):
71
+ data = getattr(model_instance, self.attname)
72
+ if data is None:
73
+ return data
74
+ clean_value = nh3.clean(data, **self.nh3_kwargs) if data else ""
75
+ setattr(model_instance, self.attname, mark_safe(clean_value))
76
+ return clean_value
77
+
78
+ def from_db_value(self, value, expression, connection):
79
+ if value is None:
80
+ return value
81
+ # Values are sanitised before saving, so any value returned from the DB
82
+ # is safe to render unescaped.
83
+ return mark_safe(value)
@@ -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-03-05 17:31+0100\n"
10
+ "POT-Creation-Date: 2025-03-18 12:26+0100\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -47,11 +47,11 @@ msgstr "Interdit"
47
47
  msgid "Resource not found"
48
48
  msgstr "Ressource non trouvée"
49
49
 
50
- #: fields.py:86
50
+ #: fields/minutes_duration_field.py:31
51
51
  msgid "Invalid value."
52
52
  msgstr "Valeur invalide."
53
53
 
54
- #: fields.py:101
54
+ #: fields/minutes_duration_field.py:46
55
55
  msgid ""
56
56
  "Invalid format, it can be a number in hours, “1:05”, “:05”, “1h 5m”, “1.5h” "
57
57
  "or “30m”."
@@ -20,3 +20,4 @@ apispec
20
20
  pyyaml
21
21
  pytz
22
22
  pyotp
23
+ nh3
@@ -40,6 +40,7 @@ install_requires =
40
40
  pyyaml
41
41
  pytz
42
42
  dill
43
+ nh3
43
44
 
44
45
  [options.extras_require]
45
46
  otp = pyotp
@@ -8,6 +8,7 @@ from .test_cache import TestCache
8
8
  from .test_client import TestApiClient
9
9
  from .test_fields_choices import TestFieldsChoices
10
10
  from .test_fields_minutes_duration import TestFieldsMinutesDuration
11
+ from .test_fields_nh3 import TestFieldsNh3
11
12
  from .test_filters import FiltersTest
12
13
  from .test_locale_api import LocaleAPITest
13
14
  from .test_ordered_rest_view_mixin import TestOrderedRestViewMixin
@@ -29,7 +29,7 @@ class TestFieldsMinutesDuration(TestAssertMixin, TestCase):
29
29
  pub_date=date(1937, 1, 1)
30
30
  )
31
31
 
32
- @patch('pfx.pfxcore.fields.logger', MagicMock())
32
+ @patch('pfx.pfxcore.fields.minutes_duration_field.logger', MagicMock())
33
33
  def test_to_python(self):
34
34
  d = MinutesDurationField()
35
35
  self.assertIsNone(d.to_python(None))
@@ -0,0 +1,38 @@
1
+ from django.db import connection, models
2
+ from django.test import TestCase
3
+ from django.test.utils import override_settings
4
+
5
+ from pfx.pfxcore.fields import NH3Field
6
+ from pfx.pfxcore.models import JSONReprMixin
7
+ from pfx.pfxcore.test import TestAssertMixin
8
+
9
+
10
+ class TestNh3Model(JSONReprMixin, models.Model):
11
+ html = NH3Field()
12
+ custom_html = NH3Field(
13
+ allowed_tags={'h1', 'p', 'span'},
14
+ allowed_attributes={'*': {'class'}})
15
+
16
+ class Meta:
17
+ verbose_name = "TestModel"
18
+ verbose_name_plural = "TestModels"
19
+ ordering = ['pk']
20
+
21
+
22
+ @override_settings(ROOT_URLCONF=__name__)
23
+ class TestFieldsNh3(TestAssertMixin, TestCase):
24
+
25
+ @classmethod
26
+ def setUpTestData(cls):
27
+ with connection.schema_editor() as schema_editor:
28
+ schema_editor.create_model(TestNh3Model)
29
+
30
+ def test_save(self):
31
+ t = TestNh3Model.objects.create(
32
+ html="<unknown>AAA</unknown>",
33
+ custom_html='<h1>TEST</h1>'
34
+ '<script>alert("hello")</script>'
35
+ '<p><span class="test" style="font-family: noto;"></span></p>')
36
+ self.assertEqual(t.html, "AAA")
37
+ self.assertEqual(
38
+ t.custom_html, '<h1>TEST</h1><p><span class="test"></span></p>')
File without changes