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