django-pfx 1.7.3.dev2__tar.gz → 1.7.3.dev6__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.7.3.dev2 → django_pfx-1.7.3.dev6}/.pre-commit-config.yaml +8 -8
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/PKG-INFO +4 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/PKG-INFO +4 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/SOURCES.txt +24 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/requires.txt +4 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/conf.py +3 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/make_messages +1 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/__init__.py +0 -2
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apps.py +15 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/default_settings.py +7 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/media_field.py +19 -1
- django_pfx-1.7.3.dev6/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +28 -14
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/__init__.py +1 -0
- django_pfx-1.7.3.dev6/pfx/pfxcore/models/attachment_mixin.py +78 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/ordered_model_mixin.py +2 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/shortcuts.py +5 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/otp_code_email.txt +1 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/password_reset_email.txt +2 -2
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/welcome_email.txt +1 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/rest_views.py +32 -25
- django_pfx-1.7.3.dev6/pfx/settings/dev.py +34 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/__init__.py +1 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/apps.py +22 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +154 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/migrations/0001_initial.py +76 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +100 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/models/__init__.py +2 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/models/user_job.py +217 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/models/user_job_attachment.py +32 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/providers/__init__.py +4 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/providers/user_job_django_q_executor.py +29 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/providers/user_job_websocket_channel_provider.py +30 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/tasks.py +93 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/urls.py +14 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/views/__init__.py +3 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/views/user_job_attachment_view.py +17 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/views/user_job_view.py +63 -0
- django_pfx-1.7.3.dev6/pfx/userjobs/views/user_websocket_consumer.py +65 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/requirements.txt +7 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/setup.cfg +1 -0
- django_pfx-1.7.3.dev6/tests/channel_group_send_calls.py +21 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/settings/common.py +28 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/__init__.py +3 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_auth_api.py +17 -14
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_profiling_middleware.py +0 -1
- django_pfx-1.7.3.dev6/tests/tests/test_user_job_api.py +574 -0
- django_pfx-1.7.3.dev6/tests/tests/test_user_job_messages.py +128 -0
- django_pfx-1.7.3.dev6/tests/tests/test_user_job_model.py +302 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/urls.py +2 -1
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/settings/common.py +26 -0
- django_pfx-1.7.3.dev6/tests_custom_user/settings/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/common.py +26 -0
- django_pfx-1.7.3.dev2/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- django_pfx-1.7.3.dev2/pfx/settings/dev.py +0 -8
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/.gitignore +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/.gitlab-ci.yml +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/LICENSE +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/MANIFEST.in +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/README.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/Makefile +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/index.rst +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/api.views.rst +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/authentication.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/decorator.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/getting_started.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/model.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/profiling.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/settings.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/doc/source/testing.md +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/img/pfx.png +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/img/pfx.svg +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/manage.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/decimal_field.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/fields/rich_text_field.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/base.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/sms/backends/console.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/exceptions.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/local_storage.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.7.3.dev2/tests → django_pfx-1.7.3.dev6/pfx/userjobs/migrations}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pyproject.toml +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/serve-doc +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/setup.py +0 -0
- {django_pfx-1.7.3.dev2/tests/migrations → django_pfx-1.7.3.dev6/tests}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/apps.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0002_alter_book_cover.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0003_book_local_file.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0004_mfausermixin_fields.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0005_mfausermixin_fields_fix.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py +0 -0
- {django_pfx-1.7.3.dev2/tests/settings → django_pfx-1.7.3.dev6/tests/migrations}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/models.py +0 -0
- {django_pfx-1.7.3.dev2/tests_base_user → django_pfx-1.7.3.dev6/tests/settings}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/settings/ci.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/settings/dev.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_client.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_choices.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_date.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_decimal.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_minutes_duration.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_one2many.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_rich_text.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_fields_time.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_post_migrate_groups_update.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests/views.py +0 -0
- {django_pfx-1.7.3.dev2/tests_base_user/migrations → django_pfx-1.7.3.dev6/tests_base_user}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.3.dev2/tests_base_user/settings → django_pfx-1.7.3.dev6/tests_base_user/migrations}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2/tests_custom_user → django_pfx-1.7.3.dev6/tests_base_user/settings}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/settings/ci.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/tests/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/tests/test_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/urls.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_base_user/views.py +0 -0
- {django_pfx-1.7.3.dev2/tests_custom_user/migrations → django_pfx-1.7.3.dev6/tests_custom_user}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.3.dev2/tests_custom_user/settings → django_pfx-1.7.3.dev6/tests_custom_user/migrations}/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/models.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/ci.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/__init__.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/test_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/urls.py +0 -0
- {django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/tests_custom_user/views.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
repos:
|
|
2
|
-
-
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
3
|
rev: v4.3.0
|
|
4
4
|
hooks:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
5
|
+
- id: check-yaml
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: trailing-whitespace
|
|
8
|
+
- repo: local
|
|
9
9
|
hooks:
|
|
10
10
|
- id: flake8
|
|
11
11
|
name: flake8
|
|
@@ -13,17 +13,17 @@ repos:
|
|
|
13
13
|
language: system
|
|
14
14
|
types: [python]
|
|
15
15
|
args: [--config=./setup.cfg]
|
|
16
|
-
-
|
|
16
|
+
- repo: local
|
|
17
17
|
hooks:
|
|
18
18
|
- id: isort
|
|
19
19
|
name: isort
|
|
20
20
|
entry: isort
|
|
21
21
|
language: system
|
|
22
22
|
types: [python]
|
|
23
|
-
-
|
|
23
|
+
- repo: local
|
|
24
24
|
hooks:
|
|
25
25
|
- id: make-messages
|
|
26
26
|
name: make messages
|
|
27
27
|
entry: ./make_messages
|
|
28
28
|
language: system
|
|
29
|
-
|
|
29
|
+
pass_filenames: false
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.3.
|
|
3
|
+
Version: 1.7.3.dev6
|
|
4
4
|
Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
|
|
5
5
|
Author: Hervé Martinet
|
|
6
6
|
Author-email: herve.martinet@gmail.com
|
|
@@ -37,6 +37,9 @@ Requires-Dist: dill
|
|
|
37
37
|
Requires-Dist: nh3
|
|
38
38
|
Provides-Extra: otp
|
|
39
39
|
Requires-Dist: pyotp; extra == "otp"
|
|
40
|
+
Provides-Extra: heic-converter
|
|
41
|
+
Requires-Dist: python-magic; extra == "heic-converter"
|
|
42
|
+
Requires-Dist: pillow-heif; extra == "heic-converter"
|
|
40
43
|
Dynamic: license-file
|
|
41
44
|
|
|
42
45
|
# Django PFX
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.3.
|
|
3
|
+
Version: 1.7.3.dev6
|
|
4
4
|
Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
|
|
5
5
|
Author: Hervé Martinet
|
|
6
6
|
Author-email: herve.martinet@gmail.com
|
|
@@ -37,6 +37,9 @@ Requires-Dist: dill
|
|
|
37
37
|
Requires-Dist: nh3
|
|
38
38
|
Provides-Extra: otp
|
|
39
39
|
Requires-Dist: pyotp; extra == "otp"
|
|
40
|
+
Provides-Extra: heic-converter
|
|
41
|
+
Requires-Dist: python-magic; extra == "heic-converter"
|
|
42
|
+
Requires-Dist: pillow-heif; extra == "heic-converter"
|
|
40
43
|
Dynamic: license-file
|
|
41
44
|
|
|
42
45
|
# Django PFX
|
|
@@ -73,6 +73,7 @@ pfx/pfxcore/migrations/operations/__init__.py
|
|
|
73
73
|
pfx/pfxcore/migrations/operations/permissions.py
|
|
74
74
|
pfx/pfxcore/models/__init__.py
|
|
75
75
|
pfx/pfxcore/models/abstract_pfx_base_user.py
|
|
76
|
+
pfx/pfxcore/models/attachment_mixin.py
|
|
76
77
|
pfx/pfxcore/models/cache_mixins.py
|
|
77
78
|
pfx/pfxcore/models/login_ban.py
|
|
78
79
|
pfx/pfxcore/models/mfa_user_mixin.py
|
|
@@ -125,8 +126,28 @@ pfx/pfxcore/views/parameters/subset_page_size.py
|
|
|
125
126
|
pfx/pfxcore/views/parameters/subset_page_subset.py
|
|
126
127
|
pfx/settings/__init__.py
|
|
127
128
|
pfx/settings/dev.py
|
|
129
|
+
pfx/userjobs/__init__.py
|
|
130
|
+
pfx/userjobs/apps.py
|
|
131
|
+
pfx/userjobs/tasks.py
|
|
132
|
+
pfx/userjobs/urls.py
|
|
133
|
+
pfx/userjobs/locale/fr/LC_MESSAGES/django.mo
|
|
134
|
+
pfx/userjobs/locale/fr/LC_MESSAGES/django.po
|
|
135
|
+
pfx/userjobs/migrations/0001_initial.py
|
|
136
|
+
pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py
|
|
137
|
+
pfx/userjobs/migrations/__init__.py
|
|
138
|
+
pfx/userjobs/models/__init__.py
|
|
139
|
+
pfx/userjobs/models/user_job.py
|
|
140
|
+
pfx/userjobs/models/user_job_attachment.py
|
|
141
|
+
pfx/userjobs/providers/__init__.py
|
|
142
|
+
pfx/userjobs/providers/user_job_django_q_executor.py
|
|
143
|
+
pfx/userjobs/providers/user_job_websocket_channel_provider.py
|
|
144
|
+
pfx/userjobs/views/__init__.py
|
|
145
|
+
pfx/userjobs/views/user_job_attachment_view.py
|
|
146
|
+
pfx/userjobs/views/user_job_view.py
|
|
147
|
+
pfx/userjobs/views/user_websocket_consumer.py
|
|
128
148
|
tests/__init__.py
|
|
129
149
|
tests/apps.py
|
|
150
|
+
tests/channel_group_send_calls.py
|
|
130
151
|
tests/models.py
|
|
131
152
|
tests/urls.py
|
|
132
153
|
tests/views.py
|
|
@@ -172,6 +193,9 @@ tests/tests/test_settings.py
|
|
|
172
193
|
tests/tests/test_shortcuts.py
|
|
173
194
|
tests/tests/test_timezone_middleware.py
|
|
174
195
|
tests/tests/test_tools.py
|
|
196
|
+
tests/tests/test_user_job_api.py
|
|
197
|
+
tests/tests/test_user_job_messages.py
|
|
198
|
+
tests/tests/test_user_job_model.py
|
|
175
199
|
tests/tests/test_user_queryset.py
|
|
176
200
|
tests/tests/test_view_decorators.py
|
|
177
201
|
tests/tests/test_view_fields.py
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import logging
|
|
3
|
+
import os
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from django import apps
|
|
@@ -88,9 +89,22 @@ class PfxAppConfig(AppConfig):
|
|
|
88
89
|
|
|
89
90
|
def ready(self):
|
|
90
91
|
post_migrate.connect(update_groups_permissions_action, sender=self)
|
|
91
|
-
|
|
92
|
+
super().ready()
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
class PfxCoreConfig(AppConfig):
|
|
95
96
|
name = 'pfx.pfxcore'
|
|
96
97
|
default = True
|
|
98
|
+
|
|
99
|
+
def ready(self):
|
|
100
|
+
if os.environ.get("RUN_MAIN") == "true":
|
|
101
|
+
try:
|
|
102
|
+
from pillow_heif import register_heif_opener
|
|
103
|
+
register_heif_opener()
|
|
104
|
+
logger.info("PFX HEIC opener registered.")
|
|
105
|
+
except Exception:
|
|
106
|
+
logger.warning(
|
|
107
|
+
"PFX HEIC opener not registered "
|
|
108
|
+
"(use `pip install django-pfx[heic-converter]` "
|
|
109
|
+
"to use it.)")
|
|
110
|
+
super().ready()
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from django.utils.translation import gettext_lazy as _
|
|
2
|
+
|
|
1
3
|
PFX_TOKEN_SHORT_VALIDITY = {'hours': 12}
|
|
2
4
|
PFX_TOKEN_LONG_VALIDITY = {'days': 30}
|
|
3
5
|
PFX_TOKEN_OTP_VALIDITY = {'minutes': 15}
|
|
@@ -42,3 +44,8 @@ PFX_MFA_BACKENDS = ["authenticator", "email"]
|
|
|
42
44
|
PFX_MFA_FORCE = False
|
|
43
45
|
|
|
44
46
|
PFX_SMS_BACKEND = 'pfx.pfxcore.sms.backends.console.ConsoleSMSBackend'
|
|
47
|
+
|
|
48
|
+
# PFX assume you have a log monitoring system (like Sentry), but
|
|
49
|
+
# you can adapt the message to your use case.
|
|
50
|
+
PFX_SYSTEM_ERROR_USER_MESSAGE = _(
|
|
51
|
+
"A system error occurred. Our support team has been notified.")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import logging
|
|
2
3
|
from importlib import import_module
|
|
3
4
|
from urllib.request import urlopen
|
|
@@ -42,7 +43,8 @@ def validate_media_json(value):
|
|
|
42
43
|
class MediaField(models.JSONField):
|
|
43
44
|
def __init__(
|
|
44
45
|
self, *args, max_length=255, get_key=None, storage=None,
|
|
45
|
-
auto_delete=False, extra_keys=None,
|
|
46
|
+
auto_delete=False, extra_keys=None,
|
|
47
|
+
convert_heic=False, **kwargs):
|
|
46
48
|
self.get_key = get_key or self.get_default_key
|
|
47
49
|
if not storage and not settings.STORAGE_DEFAULT:
|
|
48
50
|
raise Exception(
|
|
@@ -51,6 +53,7 @@ class MediaField(models.JSONField):
|
|
|
51
53
|
self.storage = storage or get_storage_class(settings.STORAGE_DEFAULT)
|
|
52
54
|
self.auto_delete = auto_delete
|
|
53
55
|
self.allowed_keys = DEFAULT_KEYS.union(extra_keys or set())
|
|
56
|
+
self.convert_heic = convert_heic
|
|
54
57
|
self._db_value = None
|
|
55
58
|
|
|
56
59
|
# Inject default validator if empty
|
|
@@ -107,9 +110,24 @@ class MediaField(models.JSONField):
|
|
|
107
110
|
request, self.value_from_object(obj)['key'])
|
|
108
111
|
|
|
109
112
|
def upload(self, obj, file, filename, **kwargs):
|
|
113
|
+
if self.convert_heic:
|
|
114
|
+
file, filename = self.convert_heic_file(file, filename)
|
|
110
115
|
key = self.get_key(obj, filename)
|
|
111
116
|
return self.to_python(self.storage.upload(key, file, **kwargs))
|
|
112
117
|
|
|
118
|
+
def convert_heic_file(self, file, filename):
|
|
119
|
+
import magic
|
|
120
|
+
from PIL import Image
|
|
121
|
+
mime_type = magic.from_buffer(file, mime=True)
|
|
122
|
+
if mime_type in ('image/heic', 'image/heif'):
|
|
123
|
+
img = Image.open(io.BytesIO(file))
|
|
124
|
+
buf = io.BytesIO()
|
|
125
|
+
img.convert("RGB").save(buf, format="PNG")
|
|
126
|
+
|
|
127
|
+
file = buf.getvalue()
|
|
128
|
+
filename = filename.rsplit(".", 1)[0] + '.png'
|
|
129
|
+
return file, filename
|
|
130
|
+
|
|
113
131
|
def delete(self, value):
|
|
114
132
|
return self.storage.delete(value)
|
|
115
133
|
|
|
Binary file
|
|
@@ -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: 2026-
|
|
10
|
+
"POT-Creation-Date: 2026-05-21 16:23+0200\n"
|
|
11
11
|
"PO-Revision-Date: 2021-06-22 23:31+0200\n"
|
|
12
12
|
"Last-Translator: \n"
|
|
13
13
|
"Language-Team: \n"
|
|
@@ -22,6 +22,12 @@ msgstr ""
|
|
|
22
22
|
msgid "An internal server error occured."
|
|
23
23
|
msgstr "Une erreur interne du serveur est survenue."
|
|
24
24
|
|
|
25
|
+
#: default_settings.py:51
|
|
26
|
+
msgid "A system error occurred. Our support team has been notified."
|
|
27
|
+
msgstr ""
|
|
28
|
+
"Une erreur système s’est produite. "
|
|
29
|
+
"Notre équipe d’assistance en a été informée."
|
|
30
|
+
|
|
25
31
|
#: exceptions.py:53 exceptions.py:76
|
|
26
32
|
#, python-brace-format
|
|
27
33
|
msgid "{model} not found."
|
|
@@ -67,6 +73,10 @@ msgstr "utilisateur"
|
|
|
67
73
|
msgid "users"
|
|
68
74
|
msgstr "utilisateurs"
|
|
69
75
|
|
|
76
|
+
#: models/attachment_mixin.py:25
|
|
77
|
+
msgid "File"
|
|
78
|
+
msgstr "Fichier"
|
|
79
|
+
|
|
70
80
|
#: models/login_ban.py:54
|
|
71
81
|
msgid "Username"
|
|
72
82
|
msgstr "Nom d’utilisateur"
|
|
@@ -139,10 +149,14 @@ msgstr "Configuration MFA requise"
|
|
|
139
149
|
msgid "Is MFA forced"
|
|
140
150
|
msgstr "MFA est forcé"
|
|
141
151
|
|
|
152
|
+
#: models/ordered_model_mixin.py:10
|
|
153
|
+
msgid "Sequence"
|
|
154
|
+
msgstr "Séquence"
|
|
155
|
+
|
|
142
156
|
#: models/pfx_models.py:14
|
|
143
157
|
#, python-format
|
|
144
158
|
msgid "%(model_name)s with this %(field_labels)s already exists."
|
|
145
|
-
msgstr "%(model_name)s avec ce/cette %(field_labels)s
|
|
159
|
+
msgstr "%(model_name)s avec ce/cette %(field_labels)s existe déjà."
|
|
146
160
|
|
|
147
161
|
#: shortcuts.py:52
|
|
148
162
|
#, python-brace-format
|
|
@@ -172,7 +186,7 @@ msgstr "{key} doit être « true », « false », « 1 », « 0
|
|
|
172
186
|
#: templates/registration/otp_code_email.txt:2
|
|
173
187
|
#, python-format
|
|
174
188
|
msgid ""
|
|
175
|
-
"You
|
|
189
|
+
"You’re receiving this email because you requested an authentication code at "
|
|
176
190
|
"%(site_name)s."
|
|
177
191
|
msgstr ""
|
|
178
192
|
"Vous recevez cet e-mail parce que vous avez demandé un code d’authentication "
|
|
@@ -191,14 +205,14 @@ msgstr "Ce code est valable durant %(otp_validity)s minutes."
|
|
|
191
205
|
#: templates/registration/password_reset_email.txt:10
|
|
192
206
|
#: templates/registration/welcome_email.txt:10
|
|
193
207
|
msgid "Thanks for using our site!"
|
|
194
|
-
msgstr "Merci d
|
|
208
|
+
msgstr "Merci d’utiliser notre site !"
|
|
195
209
|
|
|
196
210
|
#: templates/registration/otp_code_email.txt:10
|
|
197
211
|
#: templates/registration/password_reset_email.txt:12
|
|
198
212
|
#: templates/registration/welcome_email.txt:12
|
|
199
213
|
#, python-format
|
|
200
214
|
msgid "The %(site_name)s team"
|
|
201
|
-
msgstr "L
|
|
215
|
+
msgstr "L’équipe de %(site_name)s"
|
|
202
216
|
|
|
203
217
|
#: templates/registration/otp_code_subject.txt:2
|
|
204
218
|
#, python-format
|
|
@@ -208,7 +222,7 @@ msgstr "Nouveau code d’authentication pour %(site_name)s"
|
|
|
208
222
|
#: templates/registration/password_reset_email.txt:2
|
|
209
223
|
#, python-format
|
|
210
224
|
msgid ""
|
|
211
|
-
"You
|
|
225
|
+
"You’re receiving this email because you requested a password reset for your "
|
|
212
226
|
"user account at %(site_name)s."
|
|
213
227
|
msgstr ""
|
|
214
228
|
"Vous recevez cet e-mail parce que vous avez demandé une réinitialisation du "
|
|
@@ -223,8 +237,8 @@ msgstr ""
|
|
|
223
237
|
|
|
224
238
|
#: templates/registration/password_reset_email.txt:8
|
|
225
239
|
#: templates/registration/welcome_email.txt:8
|
|
226
|
-
msgid "Your username, in case you
|
|
227
|
-
msgstr "Votre nom d
|
|
240
|
+
msgid "Your username, in case you’ve forgotten:"
|
|
241
|
+
msgstr "Votre nom d’utilisateur, au cas où vous l’auriez oublié :"
|
|
228
242
|
|
|
229
243
|
#: templates/registration/password_reset_subject.txt:2
|
|
230
244
|
#, python-format
|
|
@@ -281,11 +295,11 @@ msgstr "Un mot de passe vide n’est pas autorisé"
|
|
|
281
295
|
|
|
282
296
|
#: views/authentication_views.py:557
|
|
283
297
|
msgid "User and token are valid"
|
|
284
|
-
msgstr "L
|
|
298
|
+
msgstr "L’utilisateur et le token sont valides"
|
|
285
299
|
|
|
286
300
|
#: views/authentication_views.py:559
|
|
287
301
|
msgid "User or token is invalid"
|
|
288
|
-
msgstr "L
|
|
302
|
+
msgstr "L’utilisateur ou le token est invalide"
|
|
289
303
|
|
|
290
304
|
#: views/authentication_views.py:671
|
|
291
305
|
msgid "OTP is already enabled"
|
|
@@ -314,7 +328,7 @@ msgstr ""
|
|
|
314
328
|
|
|
315
329
|
#: views/authentication_views.py:1082
|
|
316
330
|
msgid "A new authentication code has been sent by email."
|
|
317
|
-
msgstr "Un nouveau code d
|
|
331
|
+
msgstr "Un nouveau code d’authentification a été envoyé par e-mail."
|
|
318
332
|
|
|
319
333
|
#: views/filters_views.py:81
|
|
320
334
|
#, python-brace-format
|
|
@@ -333,9 +347,9 @@ msgstr "Le paramètre object est requis pour move={move}."
|
|
|
333
347
|
#: views/ordered_rest_view_mixin.py:39
|
|
334
348
|
#, python-brace-format
|
|
335
349
|
msgid "object {pk} does not exists in this move context."
|
|
336
|
-
msgstr "object {pk} n
|
|
350
|
+
msgstr "object {pk} n’existe pas dans ce contexte de déplacement."
|
|
337
351
|
|
|
338
|
-
#: views/rest_views.py:228 views/rest_views.py:
|
|
352
|
+
#: views/rest_views.py:228 views/rest_views.py:385
|
|
339
353
|
#, python-brace-format
|
|
340
354
|
msgid "{obj} cannot be deleted because it is referenced by other objects."
|
|
341
355
|
msgstr ""
|
|
@@ -351,7 +365,7 @@ msgstr "{model} {obj} créé."
|
|
|
351
365
|
msgid "{model} {obj} updated."
|
|
352
366
|
msgstr "{model} {obj} modifié."
|
|
353
367
|
|
|
354
|
-
#: views/rest_views.py:
|
|
368
|
+
#: views/rest_views.py:1306
|
|
355
369
|
#, python-brace-format
|
|
356
370
|
msgid "{model} {obj} deleted."
|
|
357
371
|
msgstr "{model} {obj} supprimé."
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .abstract_pfx_base_user import AbstractPFXBaseUser, AbstractPFXUser
|
|
2
|
+
from .attachment_mixin import AttachmentMixin
|
|
2
3
|
from .cache_mixins import CacheableMixin, CacheDependsMixin
|
|
3
4
|
from .login_ban import LoginBan
|
|
4
5
|
from .mfa_user_mixin import MFAUserMixin, OtpUserMixin
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from django.db import models
|
|
5
|
+
from django.utils.module_loading import import_string
|
|
6
|
+
from django.utils.translation import gettext_lazy as _
|
|
7
|
+
|
|
8
|
+
from pfx.pfxcore.fields import MediaField
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
file_field_overrides_error = (
|
|
13
|
+
"PFX_ATTACHMENT_FILE_FIELD_OVERRIDES must be:\n"
|
|
14
|
+
"- a dict.\n"
|
|
15
|
+
"- a callable returning a dict.\n"
|
|
16
|
+
"- a dotted import path to a callable returning a dict.\n")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_file_key(obj, filename):
|
|
20
|
+
return obj.get_file_key(filename)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _get_attachment_file_field_kwargs():
|
|
24
|
+
kwargs = dict(
|
|
25
|
+
verbose_name=_("File"), get_key=_get_file_key,
|
|
26
|
+
auto_delete=True, blank=True, null=True)
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
func_path = getattr(
|
|
30
|
+
settings, 'PFX_ATTACHMENT_FILE_FIELD_OVERRIDES', None)
|
|
31
|
+
custom_kwargs = {}
|
|
32
|
+
if func_path:
|
|
33
|
+
if isinstance(func_path, dict):
|
|
34
|
+
custom_kwargs = func_path
|
|
35
|
+
elif callable(func_path):
|
|
36
|
+
custom_kwargs = func_path()
|
|
37
|
+
else:
|
|
38
|
+
custom_kwargs = import_string(func_path)()
|
|
39
|
+
if custom_kwargs:
|
|
40
|
+
kwargs.update(custom_kwargs)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise TypeError(
|
|
43
|
+
"PFX_ATTACHMENT_FILE_FIELD_OVERRIDES must be:\n"
|
|
44
|
+
"- a dict.\n"
|
|
45
|
+
"- a callable returning a dict.\n"
|
|
46
|
+
"- a dotted import path to a callable returning a dict.\n"
|
|
47
|
+
) from e
|
|
48
|
+
|
|
49
|
+
return kwargs
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class AttachmentMixin(models.Model):
|
|
53
|
+
file = MediaField(**_get_attachment_file_field_kwargs())
|
|
54
|
+
|
|
55
|
+
class Meta:
|
|
56
|
+
abstract = True
|
|
57
|
+
|
|
58
|
+
def get_file_key(self, filename):
|
|
59
|
+
raise NotImplementedError()
|
|
60
|
+
|
|
61
|
+
def __str__(self):
|
|
62
|
+
return (self.file or {}).get('name', '')
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def url(self):
|
|
66
|
+
if not getattr(self, 'api', None):
|
|
67
|
+
raise RuntimeError(
|
|
68
|
+
f"api attribute is not defined on {self.__class__}")
|
|
69
|
+
return f'{self.api}/{self.pk}/file'
|
|
70
|
+
|
|
71
|
+
def json_repr(self, **values):
|
|
72
|
+
return super().json_repr(
|
|
73
|
+
file={
|
|
74
|
+
'url': self.url,
|
|
75
|
+
'name': (self.file or {}).get('name'),
|
|
76
|
+
'content-type': (self.file or {}).get('content-type'),
|
|
77
|
+
'content-length': (self.file or {}).get('content-length')},
|
|
78
|
+
**values)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from django.db import models
|
|
2
2
|
from django.db.models import F, Max, Min
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class OrderedModelMixin(models.Model):
|
|
6
7
|
ordered_by = []
|
|
7
8
|
ordered_default = 'last'
|
|
8
9
|
|
|
9
|
-
seq = models.PositiveBigIntegerField("
|
|
10
|
+
seq = models.PositiveBigIntegerField(_("Sequence"))
|
|
10
11
|
|
|
11
12
|
class Meta:
|
|
12
13
|
abstract = True
|
|
@@ -167,3 +167,8 @@ def file_extension(filename):
|
|
|
167
167
|
return ''.join(suffixes[-2:])
|
|
168
168
|
else:
|
|
169
169
|
return suffixes[-1]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def get_system_error_user_message(context=None):
|
|
173
|
+
# use str() to force lazy gettext string to be translated.
|
|
174
|
+
return str(settings.PFX_SYSTEM_ERROR_USER_MESSAGE)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% load i18n %}{% autoescape off %}
|
|
2
|
-
{% blocktrans %}You
|
|
2
|
+
{% blocktrans %}You’re receiving this email because you requested an authentication code at {{ site_name }}.{% endblocktrans %}
|
|
3
3
|
|
|
4
4
|
{% trans "Authentication code:" %} {{ otp_code }}
|
|
5
5
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{% load i18n %}{% autoescape off %}
|
|
2
|
-
{% blocktrans %}You
|
|
2
|
+
{% blocktrans %}You’re receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
|
|
3
3
|
|
|
4
4
|
{% trans "Please go to the following page and choose a new password:" %}
|
|
5
5
|
{% block reset_link %}
|
|
6
6
|
{{ reset_url }}
|
|
7
7
|
{% endblock %}
|
|
8
|
-
{% trans "Your username, in case you
|
|
8
|
+
{% trans "Your username, in case you’ve forgotten:" %} {{ user.get_username }}
|
|
9
9
|
|
|
10
10
|
{% trans "Thanks for using our site!" %}
|
|
11
11
|
|
{django_pfx-1.7.3.dev2 → django_pfx-1.7.3.dev6}/pfx/pfxcore/templates/registration/welcome_email.txt
RENAMED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{% block reset_link %}
|
|
6
6
|
{{ reset_url }}
|
|
7
7
|
{% endblock %}
|
|
8
|
-
{% trans "Your username, in case you
|
|
8
|
+
{% trans "Your username, in case you’ve forgotten:" %} {{ user.get_username }}
|
|
9
9
|
|
|
10
10
|
{% trans "Thanks for using our site!" %}
|
|
11
11
|
|
|
@@ -368,22 +368,7 @@ class ModelResponseMixin(ModelMixin):
|
|
|
368
368
|
message=f(
|
|
369
369
|
message, model=self.model_name, obj=object))
|
|
370
370
|
|
|
371
|
-
def
|
|
372
|
-
"""Persist an object instance changes and build default response.
|
|
373
|
-
|
|
374
|
-
The default response contains the serialized instance after save and
|
|
375
|
-
a text message.
|
|
376
|
-
|
|
377
|
-
You can use :code:`rel_data` to pass values to set on related fields
|
|
378
|
-
after instance is persisted (to avoid errors if the instance does
|
|
379
|
-
not exists in database).
|
|
380
|
-
|
|
381
|
-
:param obj: The object instance
|
|
382
|
-
:param created: If object instance is created
|
|
383
|
-
:param rel_data: Values to set on related fields
|
|
384
|
-
:returns: The JSON response
|
|
385
|
-
:rtype: :class:`JsonResponse`
|
|
386
|
-
"""
|
|
371
|
+
def _save(self, obj, created=False, rel_data=None):
|
|
387
372
|
with transaction.atomic():
|
|
388
373
|
funcs = self.pre_save(obj, created=created)
|
|
389
374
|
obj.save()
|
|
@@ -412,6 +397,24 @@ class ModelResponseMixin(ModelMixin):
|
|
|
412
397
|
prev = o
|
|
413
398
|
getattr(obj, k).set(v)
|
|
414
399
|
self.post_save(obj, created=created, funcs=funcs)
|
|
400
|
+
|
|
401
|
+
def is_valid(self, obj, created=False, rel_data=None):
|
|
402
|
+
"""Persist an object instance changes and build default response.
|
|
403
|
+
|
|
404
|
+
The default response contains the serialized instance after save and
|
|
405
|
+
a text message.
|
|
406
|
+
|
|
407
|
+
You can use :code:`rel_data` to pass values to set on related fields
|
|
408
|
+
after instance is persisted (to avoid errors if the instance does
|
|
409
|
+
not exists in database).
|
|
410
|
+
|
|
411
|
+
:param obj: The object instance
|
|
412
|
+
:param created: If object instance is created
|
|
413
|
+
:param rel_data: Values to set on related fields
|
|
414
|
+
:returns: The JSON response
|
|
415
|
+
:rtype: :class:`JsonResponse`
|
|
416
|
+
"""
|
|
417
|
+
self._save(obj, created, rel_data)
|
|
415
418
|
obj = self.get_object(pk=obj.pk)
|
|
416
419
|
return self.response(
|
|
417
420
|
obj, **self.is_valid_response_meta(obj, created=created))
|
|
@@ -1229,18 +1232,22 @@ class UpdateRestViewMixin(ModelBodyMixin, ModelResponseMixin):
|
|
|
1229
1232
|
"""
|
|
1230
1233
|
return True
|
|
1231
1234
|
|
|
1235
|
+
def _fill_and_validate(self, obj):
|
|
1236
|
+
data, rel_data = self.get_model_data(
|
|
1237
|
+
obj, self.deserialize_body(), created=False)
|
|
1238
|
+
forbidden = False
|
|
1239
|
+
if not self.object_update_perm(obj, data):
|
|
1240
|
+
forbidden = True
|
|
1241
|
+
self.set_values(obj, **data)
|
|
1242
|
+
self.validate(obj, rel_data=rel_data, created=False)
|
|
1243
|
+
if forbidden:
|
|
1244
|
+
raise ForbiddenError
|
|
1245
|
+
return rel_data
|
|
1246
|
+
|
|
1232
1247
|
def _put(self, id, *args, **kwargs):
|
|
1233
1248
|
try:
|
|
1234
1249
|
obj = self.get_object(pk=id)
|
|
1235
|
-
|
|
1236
|
-
obj, self.deserialize_body(), created=False)
|
|
1237
|
-
forbidden = False
|
|
1238
|
-
if not self.object_update_perm(obj, data):
|
|
1239
|
-
forbidden = True
|
|
1240
|
-
self.set_values(obj, **data)
|
|
1241
|
-
self.validate(obj, rel_data=rel_data, created=False)
|
|
1242
|
-
if forbidden:
|
|
1243
|
-
raise ForbiddenError
|
|
1250
|
+
rel_data = self._fill_and_validate(obj)
|
|
1244
1251
|
return self.is_valid(obj, created=False, rel_data=rel_data)
|
|
1245
1252
|
except ValidationError as e:
|
|
1246
1253
|
return self.is_invalid(obj, errors=e)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
SECRET_KEY = 'fake-key'
|
|
2
|
+
INSTALLED_APPS = [
|
|
3
|
+
'django.contrib.auth',
|
|
4
|
+
'django.contrib.contenttypes',
|
|
5
|
+
'django.contrib.postgres',
|
|
6
|
+
'pfx.pfxcore',
|
|
7
|
+
'pfx.userjobs',
|
|
8
|
+
]
|
|
9
|
+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|
10
|
+
STORAGE_DEFAULT = 'pfx.pfxcore.storage.LocalStorage'
|
|
11
|
+
|
|
12
|
+
CACHE_MEMORY = {
|
|
13
|
+
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
14
|
+
'LOCATION': 'unique-snowflake',
|
|
15
|
+
}
|
|
16
|
+
CACHES = {
|
|
17
|
+
'default': CACHE_MEMORY,
|
|
18
|
+
'django-q': CACHE_MEMORY
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
CHANNEL_LAYERS = {
|
|
22
|
+
"default": {
|
|
23
|
+
"BACKEND": "channels.layers.InMemoryChannelLayer"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Q_CLUSTER = {
|
|
28
|
+
'retry': 600,
|
|
29
|
+
'timeout': 300,
|
|
30
|
+
'sync': True,
|
|
31
|
+
'catch_up': False,
|
|
32
|
+
'max_attempts': 5,
|
|
33
|
+
'orm': 'default'
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .apps import UserJobsConfig
|