django-pfx 1.4.dev66__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.dev66 → django_pfx-1.4.dev70}/.gitlab-ci.yml +6 -3
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/.pre-commit-config.yaml +7 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/PKG-INFO +1 -1
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/django_pfx.egg-info/SOURCES.txt +33 -1
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/manage.py +15 -5
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +24 -16
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/abstract_pfx_base_user.py +10 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_user.py +2 -2
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/shortcuts.py +15 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/__init__.py +3 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/authentication_views.py +4 -9
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/rest_views.py +76 -1
- django_pfx-1.4.dev70/tests/migrations/0001_initial.py +119 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/models.py +3 -57
- django_pfx-1.4.dev70/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/__init__.py +1 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_client.py +8 -2
- django_pfx-1.4.dev70/tests/tests/test_permissions.py +239 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/urls.py +2 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/views.py +21 -3
- 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.dev66 → django_pfx-1.4.dev70}/.gitignore +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/LICENSE +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/README.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/Makefile +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/conf.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/index.rst +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/img/pfx.png +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/make_messages +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/pyproject.toml +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/requirements.txt +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/serve-doc +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/setup.cfg +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/setup.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev66/tests/settings → django_pfx-1.4.dev70/tests/migrations}/__init__.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev66 → django_pfx-1.4.dev70}/tests/tests/test_view_fields.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
|
|
@@ -114,6 +114,8 @@ tests/models.py
|
|
|
114
114
|
tests/urls.py
|
|
115
115
|
tests/views.py
|
|
116
116
|
tests/locale/fr/LC_MESSAGES/django.po
|
|
117
|
+
tests/migrations/0001_initial.py
|
|
118
|
+
tests/migrations/__init__.py
|
|
117
119
|
tests/settings/__init__.py
|
|
118
120
|
tests/settings/ci.py
|
|
119
121
|
tests/settings/common.py
|
|
@@ -133,6 +135,7 @@ tests/tests/test_fields.py
|
|
|
133
135
|
tests/tests/test_filters.py
|
|
134
136
|
tests/tests/test_locale_api.py
|
|
135
137
|
tests/tests/test_perm_tests.py
|
|
138
|
+
tests/tests/test_permissions.py
|
|
136
139
|
tests/tests/test_perms_api.py
|
|
137
140
|
tests/tests/test_profiling_middleware.py
|
|
138
141
|
tests/tests/test_settings.py
|
|
@@ -141,4 +144,33 @@ tests/tests/test_timezone_middleware.py
|
|
|
141
144
|
tests/tests/test_tools.py
|
|
142
145
|
tests/tests/test_user_queryset.py
|
|
143
146
|
tests/tests/test_view_decorators.py
|
|
144
|
-
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,10 +18,20 @@ writer.MIGRATION_HEADER_TEMPLATE = """\
|
|
|
18
18
|
|
|
19
19
|
def main():
|
|
20
20
|
"""Run administrative tasks."""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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)
|
|
25
35
|
try:
|
|
26
36
|
from django.core.management import execute_from_command_line
|
|
27
37
|
except ImportError as exc:
|
|
@@ -30,7 +40,7 @@ def main():
|
|
|
30
40
|
"available on your PYTHONPATH environment variable? Did you "
|
|
31
41
|
"forget to activate a virtual environment?"
|
|
32
42
|
) from exc
|
|
33
|
-
execute_from_command_line(
|
|
43
|
+
execute_from_command_line([*argv, *options])
|
|
34
44
|
|
|
35
45
|
|
|
36
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:
|
|
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
|
|
|
@@ -259,27 +267,27 @@ msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
|
|
|
259
267
|
msgid "Invalid value for {filter} filter"
|
|
260
268
|
msgstr "Valeur invalide pour le filtre {filter}"
|
|
261
269
|
|
|
262
|
-
#: views/rest_views.py:
|
|
270
|
+
#: views/rest_views.py:242
|
|
263
271
|
#, python-brace-format
|
|
264
272
|
msgid "{obj} cannot be deleted because it is referenced by other objects."
|
|
265
273
|
msgstr ""
|
|
266
274
|
"{obj} ne peut pas être supprimé car il est référencé par d’autres objets."
|
|
267
275
|
|
|
268
|
-
#: views/rest_views.py:
|
|
276
|
+
#: views/rest_views.py:342
|
|
269
277
|
#, python-brace-format
|
|
270
278
|
msgid "{model} {obj} created."
|
|
271
279
|
msgstr "{model} {obj} créé."
|
|
272
280
|
|
|
273
|
-
#: views/rest_views.py:
|
|
281
|
+
#: views/rest_views.py:343
|
|
274
282
|
#, python-brace-format
|
|
275
283
|
msgid "{model} {obj} updated."
|
|
276
284
|
msgstr "{model} {obj} modifié."
|
|
277
285
|
|
|
278
|
-
#: views/rest_views.py:
|
|
286
|
+
#: views/rest_views.py:1141
|
|
279
287
|
#, python-brace-format
|
|
280
288
|
msgid "{model} {obj} deleted."
|
|
281
289
|
msgstr "{model} {obj} supprimé."
|
|
282
290
|
|
|
283
|
-
#: views/rest_views.py:
|
|
291
|
+
#: views/rest_views.py:1240 views/rest_views.py:1280
|
|
284
292
|
msgid "Unexpected storage error"
|
|
285
293
|
msgstr "Erreur de stockage inattendue"
|
|
@@ -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"
|
|
@@ -121,3 +121,18 @@ def register_views(*views):
|
|
|
121
121
|
|
|
122
122
|
def class_key(cls, *args):
|
|
123
123
|
return f"{cls.__module__}.{cls.__name__}{''.join(f'.{a}' for a in args)}"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def permissions(*perms):
|
|
127
|
+
from django.contrib.auth.models import Permission
|
|
128
|
+
pks = set()
|
|
129
|
+
for perm in perms:
|
|
130
|
+
app_label, codename = perm.split('.')
|
|
131
|
+
pks.add(Permission.objects.get(
|
|
132
|
+
codename=codename, content_type__app_label=app_label).pk)
|
|
133
|
+
return Permission.objects.filter(pk__in=pks)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def model_permissions(model, *actions):
|
|
137
|
+
meta = model._meta
|
|
138
|
+
return {f"{meta.app_label}.{a}_{meta.model_name}" for a in actions}
|
|
@@ -15,13 +15,16 @@ from .rest_views import (
|
|
|
15
15
|
DeleteRestViewMixin,
|
|
16
16
|
DetailRestViewMixin,
|
|
17
17
|
ListRestViewMixin,
|
|
18
|
+
MediaPermsRestViewMixin,
|
|
18
19
|
MediaRestViewMixin,
|
|
19
20
|
ModelBodyMixin,
|
|
20
21
|
ModelMixin,
|
|
21
22
|
ModelResponseMixin,
|
|
23
|
+
PermsRestView,
|
|
22
24
|
RestView,
|
|
23
25
|
SecuredRestViewMixin,
|
|
24
26
|
SlugDetailRestViewMixin,
|
|
27
|
+
SlugPermsDetailRestViewMixin,
|
|
25
28
|
UpdateRestViewMixin,
|
|
26
29
|
resource_not_found,
|
|
27
30
|
)
|
|
@@ -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)
|
|
@@ -34,7 +34,14 @@ from pfx.pfxcore.exceptions import (
|
|
|
34
34
|
from pfx.pfxcore.fields import MediaField
|
|
35
35
|
from pfx.pfxcore.http import JsonResponse
|
|
36
36
|
from pfx.pfxcore.models import JSONReprMixin, UserFilteredQuerySetMixin
|
|
37
|
-
from pfx.pfxcore.shortcuts import
|
|
37
|
+
from pfx.pfxcore.shortcuts import (
|
|
38
|
+
class_key,
|
|
39
|
+
f,
|
|
40
|
+
get_bool,
|
|
41
|
+
get_int,
|
|
42
|
+
get_object,
|
|
43
|
+
model_permissions,
|
|
44
|
+
)
|
|
38
45
|
from pfx.pfxcore.storage.s3_storage import StorageException
|
|
39
46
|
|
|
40
47
|
from . import parameters
|
|
@@ -242,6 +249,12 @@ class ModelMixin():
|
|
|
242
249
|
return cls.tags or [
|
|
243
250
|
Tag(str(cls.model._meta.verbose_name))]
|
|
244
251
|
|
|
252
|
+
@classmethod
|
|
253
|
+
def get_model_perms(cls, actions):
|
|
254
|
+
"""Get the model permission name for the action.
|
|
255
|
+
"""
|
|
256
|
+
return model_permissions(cls.model, actions)
|
|
257
|
+
|
|
245
258
|
|
|
246
259
|
class ModelResponseMixin(ModelMixin):
|
|
247
260
|
"""Extension of :class:`ModelMixin` to manage object responses."""
|
|
@@ -894,6 +907,13 @@ class ListRestViewMixin(ModelResponseMixin):
|
|
|
894
907
|
cls.meta_list_schema, cls.model_list_schema]
|
|
895
908
|
|
|
896
909
|
|
|
910
|
+
class ListPermsRestViewMixin(ListRestViewMixin):
|
|
911
|
+
"""Extension mixin to check permissions."""
|
|
912
|
+
|
|
913
|
+
def get_list_perm(self, *args, **kwargs):
|
|
914
|
+
return self.request.user.has_perm(*self.get_model_perms('view'))
|
|
915
|
+
|
|
916
|
+
|
|
897
917
|
class DetailRestViewMixin(ModelResponseMixin):
|
|
898
918
|
"""Extension mixin to add a get detail route."""
|
|
899
919
|
|
|
@@ -917,6 +937,13 @@ class DetailRestViewMixin(ModelResponseMixin):
|
|
|
917
937
|
return self.response(obj)
|
|
918
938
|
|
|
919
939
|
|
|
940
|
+
class DetailPermsRestViewMixin(DetailRestViewMixin):
|
|
941
|
+
"""Extension mixin to check permissions."""
|
|
942
|
+
|
|
943
|
+
def get_perm(self, *args, **kwargs):
|
|
944
|
+
return self.request.user.has_perm(*self.get_model_perms('view'))
|
|
945
|
+
|
|
946
|
+
|
|
920
947
|
class SlugDetailRestViewMixin(ModelResponseMixin):
|
|
921
948
|
"""Extension mixin to add a get detail by slug route."""
|
|
922
949
|
|
|
@@ -944,6 +971,13 @@ class SlugDetailRestViewMixin(ModelResponseMixin):
|
|
|
944
971
|
return self.response(obj)
|
|
945
972
|
|
|
946
973
|
|
|
974
|
+
class SlugPermsDetailRestViewMixin(SlugDetailRestViewMixin):
|
|
975
|
+
"""Extension mixin to check permissions."""
|
|
976
|
+
|
|
977
|
+
def get_by_slug_perm(self, *args, **kwargs):
|
|
978
|
+
return self.request.user.has_perm(*self.get_model_perms('view'))
|
|
979
|
+
|
|
980
|
+
|
|
947
981
|
class CreateRestViewMixin(ModelBodyMixin, ModelResponseMixin):
|
|
948
982
|
"""Extension mixin to add create route."""
|
|
949
983
|
|
|
@@ -1013,6 +1047,13 @@ class CreateRestViewMixin(ModelBodyMixin, ModelResponseMixin):
|
|
|
1013
1047
|
return self._post(*args, **kwargs)
|
|
1014
1048
|
|
|
1015
1049
|
|
|
1050
|
+
class CreatePermsRestViewMixin(CreateRestViewMixin):
|
|
1051
|
+
"""Extension mixin to check permissions."""
|
|
1052
|
+
|
|
1053
|
+
def post_perm(self, *args, **kwargs):
|
|
1054
|
+
return self.request.user.has_perm(*self.get_model_perms('add'))
|
|
1055
|
+
|
|
1056
|
+
|
|
1016
1057
|
class UpdateRestViewMixin(ModelBodyMixin, ModelResponseMixin):
|
|
1017
1058
|
"""Extension mixin to add create route."""
|
|
1018
1059
|
|
|
@@ -1068,6 +1109,13 @@ class UpdateRestViewMixin(ModelBodyMixin, ModelResponseMixin):
|
|
|
1068
1109
|
return self._put(id, *args, **kwargs)
|
|
1069
1110
|
|
|
1070
1111
|
|
|
1112
|
+
class UpdatePermsRestViewMixin(UpdateRestViewMixin):
|
|
1113
|
+
"""Extension mixin to check permissions."""
|
|
1114
|
+
|
|
1115
|
+
def put_perm(self, *args, **kwargs):
|
|
1116
|
+
return self.request.user.has_perm(*self.get_model_perms('change'))
|
|
1117
|
+
|
|
1118
|
+
|
|
1071
1119
|
class DeleteRestViewMixin(ModelMixin):
|
|
1072
1120
|
"""Extension mixin to add delete route."""
|
|
1073
1121
|
|
|
@@ -1111,6 +1159,13 @@ class DeleteRestViewMixin(ModelMixin):
|
|
|
1111
1159
|
return self._delete(id, *args, **kwargs)
|
|
1112
1160
|
|
|
1113
1161
|
|
|
1162
|
+
class DeletePermsRestViewMixin(DeleteRestViewMixin):
|
|
1163
|
+
"""Extension mixin to check permissions."""
|
|
1164
|
+
|
|
1165
|
+
def delete_perm(self, *args, **kwargs):
|
|
1166
|
+
return self.request.user.has_perm(*self.get_model_perms('delete'))
|
|
1167
|
+
|
|
1168
|
+
|
|
1114
1169
|
class MediaRestViewMixin(ModelMixin):
|
|
1115
1170
|
"""Extension mixin to manage media fields."""
|
|
1116
1171
|
|
|
@@ -1228,6 +1283,16 @@ class MediaRestViewMixin(ModelMixin):
|
|
|
1228
1283
|
return JsonResponse(dict(url=url))
|
|
1229
1284
|
|
|
1230
1285
|
|
|
1286
|
+
class MediaPermsRestViewMixin(MediaRestViewMixin):
|
|
1287
|
+
"""Extension mixin to check permissions."""
|
|
1288
|
+
|
|
1289
|
+
def field_media_upload_url_perm(self, *args, **kwargs):
|
|
1290
|
+
return self.request.user.has_perm(*self.get_model_perms('change'))
|
|
1291
|
+
|
|
1292
|
+
def field_media_get_perm(self, *args, **kwargs):
|
|
1293
|
+
return self.request.user.has_perm(*self.get_model_perms('view'))
|
|
1294
|
+
|
|
1295
|
+
|
|
1231
1296
|
class SecuredRestViewMixin(View):
|
|
1232
1297
|
"""A view mixin to manage service permissions.
|
|
1233
1298
|
|
|
@@ -1409,3 +1474,13 @@ class RestView(
|
|
|
1409
1474
|
DeleteRestViewMixin,
|
|
1410
1475
|
BaseRestView):
|
|
1411
1476
|
pass
|
|
1477
|
+
|
|
1478
|
+
|
|
1479
|
+
class PermsRestView(
|
|
1480
|
+
ListPermsRestViewMixin,
|
|
1481
|
+
DetailPermsRestViewMixin,
|
|
1482
|
+
CreatePermsRestViewMixin,
|
|
1483
|
+
UpdatePermsRestViewMixin,
|
|
1484
|
+
DeletePermsRestViewMixin,
|
|
1485
|
+
BaseRestView):
|
|
1486
|
+
pass
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Generated by Django 4.2.17 on 2025-01-21 08:32
|
|
2
|
+
# flake8: noqa
|
|
3
|
+
|
|
4
|
+
import django.contrib.auth.models
|
|
5
|
+
import django.contrib.auth.validators
|
|
6
|
+
import django.db.models.deletion
|
|
7
|
+
import django.utils.timezone
|
|
8
|
+
from django.db import migrations, models
|
|
9
|
+
|
|
10
|
+
import pfx.pfxcore.fields
|
|
11
|
+
import pfx.pfxcore.models.cache_mixins
|
|
12
|
+
import pfx.pfxcore.models.not_null_fields
|
|
13
|
+
import pfx.pfxcore.models.pfx_models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Migration(migrations.Migration):
|
|
17
|
+
|
|
18
|
+
initial = True
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
('auth', '0012_alter_user_first_name_max_length'),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
operations = [
|
|
25
|
+
migrations.CreateModel(
|
|
26
|
+
name='Author',
|
|
27
|
+
fields=[
|
|
28
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
29
|
+
('first_name', models.CharField(max_length=30, verbose_name='First Name')),
|
|
30
|
+
('last_name', models.CharField(max_length=30, verbose_name='Last Name')),
|
|
31
|
+
('slug', models.SlugField(unique=True, verbose_name='Slug')),
|
|
32
|
+
('gender', models.CharField(choices=[('male', 'Male'), ('female', 'Female')], default='male', max_length=10, verbose_name='Gender')),
|
|
33
|
+
('science_fiction', models.BooleanField(default=False, verbose_name='Science Fiction')),
|
|
34
|
+
('created_at', models.DateField(auto_now_add=True, verbose_name='Created at')),
|
|
35
|
+
('create_comment', pfx.pfxcore.models.not_null_fields.NotNullCharField(blank=True, max_length=255, verbose_name='Create comment')),
|
|
36
|
+
('update_comment', pfx.pfxcore.models.not_null_fields.NotNullCharField(blank=True, max_length=255, verbose_name='Update comment')),
|
|
37
|
+
('website', pfx.pfxcore.models.not_null_fields.NotNullURLField(blank=True, max_length=255, verbose_name='Website')),
|
|
38
|
+
],
|
|
39
|
+
options={
|
|
40
|
+
'verbose_name': 'Author',
|
|
41
|
+
'verbose_name_plural': 'Authors',
|
|
42
|
+
'ordering': ['last_name', 'first_name', 'pk'],
|
|
43
|
+
},
|
|
44
|
+
bases=(pfx.pfxcore.models.cache_mixins.CacheableMixin, pfx.pfxcore.models.pfx_models.JSONReprMixin, models.Model),
|
|
45
|
+
),
|
|
46
|
+
migrations.CreateModel(
|
|
47
|
+
name='BookType',
|
|
48
|
+
fields=[
|
|
49
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
50
|
+
('name', models.CharField(max_length=30, verbose_name='Name')),
|
|
51
|
+
('slug', models.SlugField(verbose_name='Slug')),
|
|
52
|
+
],
|
|
53
|
+
options={
|
|
54
|
+
'verbose_name': 'Book Type',
|
|
55
|
+
'verbose_name_plural': 'Book Types',
|
|
56
|
+
},
|
|
57
|
+
bases=(pfx.pfxcore.models.cache_mixins.CacheDependsMixin, pfx.pfxcore.models.pfx_models.PFXModelMixin, models.Model),
|
|
58
|
+
),
|
|
59
|
+
migrations.CreateModel(
|
|
60
|
+
name='Book',
|
|
61
|
+
fields=[
|
|
62
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
63
|
+
('name', models.CharField(max_length=100, verbose_name='Name')),
|
|
64
|
+
('pub_date', models.DateField(verbose_name='Pub Date')),
|
|
65
|
+
('created_at', models.DateField(auto_now_add=True, verbose_name='Created at')),
|
|
66
|
+
('pages', models.IntegerField(blank=True, null=True, verbose_name='Pages')),
|
|
67
|
+
('rating', models.FloatField(blank=True, null=True, verbose_name='Rating')),
|
|
68
|
+
('reference', models.CharField(blank=True, max_length=30, null=True, verbose_name='Reference')),
|
|
69
|
+
('cover', pfx.pfxcore.fields.MediaField(blank=True, default=dict, max_length=255, verbose_name='Cover')),
|
|
70
|
+
('read_time', pfx.pfxcore.fields.MinutesDurationField(blank=True, null=True, verbose_name='Read Time')),
|
|
71
|
+
('author', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='books', to='tests.author', verbose_name='Author')),
|
|
72
|
+
('type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='books', to='tests.booktype', verbose_name='Book Type')),
|
|
73
|
+
],
|
|
74
|
+
options={
|
|
75
|
+
'verbose_name': 'Book',
|
|
76
|
+
'verbose_name_plural': 'Books',
|
|
77
|
+
},
|
|
78
|
+
bases=(pfx.pfxcore.models.cache_mixins.CacheDependsMixin, pfx.pfxcore.models.pfx_models.PFXModelMixin, models.Model),
|
|
79
|
+
),
|
|
80
|
+
migrations.AddField(
|
|
81
|
+
model_name='author',
|
|
82
|
+
name='types',
|
|
83
|
+
field=models.ManyToManyField(related_name='authors', to='tests.booktype', verbose_name='Types'),
|
|
84
|
+
),
|
|
85
|
+
migrations.CreateModel(
|
|
86
|
+
name='User',
|
|
87
|
+
fields=[
|
|
88
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
89
|
+
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
90
|
+
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
91
|
+
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
92
|
+
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
93
|
+
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
|
94
|
+
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
95
|
+
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
|
96
|
+
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
97
|
+
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
98
|
+
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
99
|
+
('otp_secret_token', models.CharField(blank=True, max_length=32, null=True, unique=True, verbose_name='OTP secret token')),
|
|
100
|
+
('otp_secret_token_tmp', models.CharField(blank=True, max_length=32, null=True, verbose_name='Temporary OTP secret token')),
|
|
101
|
+
('hotp_count', models.IntegerField(default=0, verbose_name='HOTP count')),
|
|
102
|
+
('hotp_expiry', models.DateTimeField(default=django.utils.timezone.now, verbose_name='HOTP expiry')),
|
|
103
|
+
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
|
104
|
+
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
|
105
|
+
],
|
|
106
|
+
options={
|
|
107
|
+
'verbose_name': 'user',
|
|
108
|
+
'verbose_name_plural': 'users',
|
|
109
|
+
},
|
|
110
|
+
bases=(pfx.pfxcore.models.cache_mixins.CacheableMixin, pfx.pfxcore.models.pfx_models.PFXModelMixin, models.Model),
|
|
111
|
+
managers=[
|
|
112
|
+
('objects', django.contrib.auth.models.UserManager()),
|
|
113
|
+
],
|
|
114
|
+
),
|
|
115
|
+
migrations.AddConstraint(
|
|
116
|
+
model_name='book',
|
|
117
|
+
constraint=pfx.pfxcore.models.pfx_models.UniqueConstraint(fields=('author', 'name'), message='%(name)s already exists for %(author)s', name='book_unique_author_and_name'),
|
|
118
|
+
),
|
|
119
|
+
]
|