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.
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.gitlab-ci.yml +6 -3
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.pre-commit-config.yaml +7 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/PKG-INFO +1 -1
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/SOURCES.txt +30 -1
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/manage.py +15 -6
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +19 -11
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/abstract_pfx_base_user.py +10 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_user.py +2 -2
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/authentication_views.py +4 -9
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/migrations/0001_initial.py +1 -14
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/models.py +0 -13
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_client.py +22 -1
- django_pfx-1.4.dev70/tests_base_user/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_base_user/migrations/0001_initial.py +13 -0
- django_pfx-1.4.dev70/tests_base_user/migrations/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_base_user/settings/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_base_user/settings/ci.py +18 -0
- django_pfx-1.4.dev70/tests_base_user/settings/common.py +80 -0
- django_pfx-1.4.dev70/tests_base_user/settings/dev.py +13 -0
- django_pfx-1.4.dev70/tests_base_user/settings/dev_custom_example.py +28 -0
- django_pfx-1.4.dev70/tests_base_user/settings/dev_default.py +12 -0
- django_pfx-1.4.dev70/tests_base_user/tests/__init__.py +2 -0
- django_pfx-1.4.dev70/tests_base_user/tests/test_api.py +32 -0
- django_pfx-1.4.dev70/tests_base_user/tests/test_auth_api.py +59 -0
- django_pfx-1.4.dev70/tests_base_user/urls.py +13 -0
- django_pfx-1.4.dev70/tests_base_user/views.py +13 -0
- django_pfx-1.4.dev70/tests_custom_user/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_custom_user/migrations/0001_initial.py +31 -0
- django_pfx-1.4.dev70/tests_custom_user/migrations/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_custom_user/models.py +18 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/__init__.py +0 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/ci.py +18 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/common.py +80 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/dev.py +13 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/dev_custom_example.py +28 -0
- django_pfx-1.4.dev70/tests_custom_user/settings/dev_default.py +12 -0
- django_pfx-1.4.dev70/tests_custom_user/tests/__init__.py +2 -0
- django_pfx-1.4.dev70/tests_custom_user/tests/test_api.py +24 -0
- django_pfx-1.4.dev70/tests_custom_user/tests/test_auth_api.py +57 -0
- django_pfx-1.4.dev70/tests_custom_user/urls.py +13 -0
- django_pfx-1.4.dev70/tests_custom_user/views.py +13 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/.gitignore +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/LICENSE +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/README.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/Makefile +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/conf.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/index.rst +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/img/pfx.png +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/make_messages +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/pyproject.toml +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/requirements.txt +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/serve-doc +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/setup.cfg +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/setup.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/__init__.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.4.dev68 → django_pfx-1.4.dev70}/tests/urls.py +0 -0
- {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
|
|
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
|
|
@@ -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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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(
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
248
|
+
#: views/authentication_views.py:527
|
|
241
249
|
msgid "OTP disabled"
|
|
242
250
|
msgstr "OTP désactivé"
|
|
243
251
|
|
|
244
|
-
#: views/authentication_views.py:
|
|
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:
|
|
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(
|
|
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
|
|
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
|
|
305
|
-
'
|
|
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
|
|
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
|
|
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
|
+
]
|
|
File without changes
|
|
File without changes
|
|
@@ -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,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
|
+
]
|