django-pfx 1.7.6.dev29__tar.gz → 1.7.6.dev33__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.6.dev29 → django_pfx-1.7.6.dev33}/PKG-INFO +1 -1
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/PKG-INFO +1 -1
- django_pfx-1.7.6.dev33/django_pfx.egg-info/scm_version.json +8 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/authentication.md +1 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/shortcuts.py +17 -3
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/mfa_device.py +16 -2
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_send_email_message.py +23 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_mfa_login_api.py +32 -0
- django_pfx-1.7.6.dev29/django_pfx.egg-info/scm_version.json +0 -8
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/.gitignore +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/.gitlab-ci.yml +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/LICENSE +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/MANIFEST.in +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/README.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/SOURCES.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/scm_file_list.json +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/Makefile +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/conf.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/index.rst +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/api.views.rst +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/decorator.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/getting_started.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/model.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/profiling.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/settings.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/testing.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/doc/source/user_jobs.md +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/img/pfx.png +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/img/pfx.svg +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/make_messages +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/manage.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/apps.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/email_backend/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/email_backend/memory_email_backend.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/email_backend/q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/exceptions.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/mailjet/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/mailjet/mailjet.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/mailjet/message_result.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0002_alter_email_headers.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0003_alter_email_options.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0004_alter_email_mail_from.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0005_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0006_alter_email_attachments.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/models/email.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/providers/email_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/tasks.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/templates/emails/base_template.html +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/templates/emails/base_template.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/templates/emails/base_template_subject.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/test.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/views/email_rest_view.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/decimal_field.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/media_field.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/rich_text_field.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/authenticator.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/base.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/email.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/legacy.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/mfa/sms.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/request_too_big_middleware.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/middleware/ws_cookie_authentication_middleware.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0007_alter_pfxuser_options.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0008_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/attachment_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/ordered_model_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/sms/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/sms/backends/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/sms/backends/base.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/sms/backends/console.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/sms/backends/memory.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/storage/exceptions.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/storage/local_storage.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/version_check.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/mfa_authentication_views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/xml_test_runner.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/apps.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0003_clean_scheduled_tasks.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0004_userjob_summary_url.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0005_swappable_user_job.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/0006_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/models/user_job.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/models/user_job_attachment.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/providers/user_job_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/providers/user_job_websocket_channel_provider.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/tasks.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/views/user_job_attachment_view.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/views/user_job_view.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/userjobs/views/user_websocket_consumer.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pyproject.toml +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/requirements.txt +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/serve-doc +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/setup.cfg +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/setup.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/apps.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/channel_group_send_calls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/mfa_urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/models.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/common.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/mfa_test_utils.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_client.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_email_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_email_model.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_test_tools.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_choices.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_date.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_decimal.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_help_text.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_minutes_duration.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_one2many.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_rich_text.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_fields_time.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_mfa_legacy.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_mfa_setup_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_post_migrate_groups_update.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_test_runner.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_user_job_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_user_job_messages.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_user_job_model.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_user_websocket.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_version_check.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_ws_cookie_middleware.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_base_user/views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/models.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user/views.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/migrations/0002_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/models.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/providers.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/scope.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/common.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/tests/test_user_job.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_custom_user_job/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/models.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/common.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/urls.py +0 -0
- {django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests_user_email_login/views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.6.
|
|
3
|
+
Version: 1.7.6.dev33
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.6.
|
|
3
|
+
Version: 1.7.6.dev33
|
|
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
|
|
@@ -188,6 +188,7 @@ removed.
|
|
|
188
188
|
* `PFX_TOKEN_OTP_VALIDITY`: Validity for OTP tokens (corresponds to the maximum time to enter
|
|
189
189
|
an OTP code after logging in with a password) (optional, default `{'minutes': 15}`)
|
|
190
190
|
* `PFX_HOTP_CODE_VALIDITY`: Validity of HOTP codes in minutes (used to send code by email or SMS) (optional, default `15`).
|
|
191
|
+
A code is accepted only once: a new one must be requested for the next verification.
|
|
191
192
|
* `PFX_OTP_VALID_WINDOW`: TOTP valid window (optional, default `1`).
|
|
192
193
|
According to [RFC 6238 section 5.2](https://www.ietf.org/rfc/rfc6238.html#section-5.2).
|
|
193
194
|
* `PFX_OTP_IMAGE`: An image https URL used by FreeOTP. See [FreeOTP URI](https://github.com/npmccallum/freeotp-android/blob/master/URI.md).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import mimetypes
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
4
5
|
from django.conf import settings
|
|
@@ -105,7 +106,9 @@ def send_email_message(
|
|
|
105
106
|
|
|
106
107
|
if attachments:
|
|
107
108
|
for att in attachments:
|
|
108
|
-
if
|
|
109
|
+
if (isinstance(getattr(att, 'file', None), dict) and
|
|
110
|
+
{'key', 'name', 'content-type'} <= att.file.keys()):
|
|
111
|
+
# Is a JSON (equivalent to MediaField)
|
|
109
112
|
fp = Path(settings.STORAGE_LOCAL_ROOT, att.file['key'])
|
|
110
113
|
if attachment_file_name and callable(attachment_file_name):
|
|
111
114
|
name = attachment_file_name(att)
|
|
@@ -118,9 +121,20 @@ def send_email_message(
|
|
|
118
121
|
except Exception as e:
|
|
119
122
|
logger.error(
|
|
120
123
|
"Error attaching file %s: %s", fp, str(e), exc_info=e)
|
|
124
|
+
elif isinstance(att, (tuple, list)):
|
|
125
|
+
# Is a tuple name, content, (mimetype)
|
|
126
|
+
if len(att) < 2:
|
|
127
|
+
logger.error(
|
|
128
|
+
"Tuple attachment must have min 2 values : %s values",
|
|
129
|
+
len(att))
|
|
130
|
+
name, content, *rest = att
|
|
131
|
+
mimetype = rest[0] if rest else mimetypes.guess_type(name)[0]
|
|
132
|
+
email.attach(
|
|
133
|
+
name, content, mimetype or 'application/octet-stream')
|
|
121
134
|
else:
|
|
122
135
|
logger.error(
|
|
123
|
-
"Attachment
|
|
124
|
-
|
|
136
|
+
"Attachment is invalid (must be a "
|
|
137
|
+
"JSON MediaField or a tuple): %s",
|
|
138
|
+
repr(att)[:100])
|
|
125
139
|
|
|
126
140
|
email.send()
|
|
@@ -66,11 +66,25 @@ class MFADevice(models.Model):
|
|
|
66
66
|
return pyotp.hotp.HOTP(self.secret).at(self.hotp_count)
|
|
67
67
|
|
|
68
68
|
def verify_hotp(self, otp_code):
|
|
69
|
-
"""Verify a HOTP code against this device's counter and expiry.
|
|
69
|
+
"""Verify a HOTP code against this device's counter and expiry.
|
|
70
|
+
|
|
71
|
+
A valid code is consumed: the counter moves on, as RFC 4226
|
|
72
|
+
requires, so the same code is refused afterwards."""
|
|
70
73
|
import pyotp
|
|
71
74
|
if not otp_code or timezone.now() > self.hotp_expiry:
|
|
72
75
|
return False
|
|
73
|
-
|
|
76
|
+
if not pyotp.hotp.HOTP(self.secret).verify(
|
|
77
|
+
otp_code, self.hotp_count):
|
|
78
|
+
return False
|
|
79
|
+
# Conditional update: of two requests with the same code, only one
|
|
80
|
+
# gets it.
|
|
81
|
+
consumed = MFADevice.objects.filter(
|
|
82
|
+
pk=self.pk, hotp_count=self.hotp_count).update(
|
|
83
|
+
hotp_count=models.F('hotp_count') + 1)
|
|
84
|
+
if not consumed:
|
|
85
|
+
return False
|
|
86
|
+
self.hotp_count += 1
|
|
87
|
+
return True
|
|
74
88
|
|
|
75
89
|
# --- TOTP (authenticator) ---
|
|
76
90
|
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/tests/tests/test_emails_send_email_message.py
RENAMED
|
@@ -52,6 +52,29 @@ class TestEmailsSendEmailMessage(TestAssertMixin, TestCase):
|
|
|
52
52
|
self.assertEqual(mail.outbox[0].attachments, [
|
|
53
53
|
('test.txt', 'A test file content.', 'text/plain')])
|
|
54
54
|
|
|
55
|
+
def test_send_email_message_in_memory_attachment(self):
|
|
56
|
+
att = "test.txt", b"A test file content.", "text/plain"
|
|
57
|
+
|
|
58
|
+
send_email_message(
|
|
59
|
+
'test@example.org', 'base_template',
|
|
60
|
+
data={'subject': "Test message"}, attachments=[att])
|
|
61
|
+
|
|
62
|
+
# Test first message
|
|
63
|
+
m = mail.outbox[0]
|
|
64
|
+
self.assertEqual(m.subject, "Test message")
|
|
65
|
+
self.assertEqual(m.to[0], 'test@example.org')
|
|
66
|
+
txt_msg = m.body
|
|
67
|
+
html_msg = m.alternatives[0][0]
|
|
68
|
+
self.assertIn(
|
|
69
|
+
'<img src="http://example.org/logo.png" alt="PFX"', html_msg)
|
|
70
|
+
self.assertIn(
|
|
71
|
+
'PFX, a DJango rest framework<br />', html_msg)
|
|
72
|
+
self.assertIn(
|
|
73
|
+
'PFX, a DJango rest framework', txt_msg)
|
|
74
|
+
|
|
75
|
+
self.assertEqual(mail.outbox[0].attachments, [
|
|
76
|
+
('test.txt', 'A test file content.', 'text/plain')])
|
|
77
|
+
|
|
55
78
|
def test_send_email_message_to_formats(self):
|
|
56
79
|
|
|
57
80
|
send_email_message(
|
|
@@ -386,6 +386,38 @@ class MFALoginTest(MFATestMixin, TestAssertMixin, TransactionTestCase):
|
|
|
386
386
|
self.assertRC(response, 200)
|
|
387
387
|
self.assertJE(response, 'user.mfa_setup_required', True)
|
|
388
388
|
|
|
389
|
+
@override_settings(PFX_MFA_BACKENDS=[SMS])
|
|
390
|
+
def test_otp_login_code_is_single_use(self):
|
|
391
|
+
"""The code that logged the user in is spent.
|
|
392
|
+
|
|
393
|
+
It used to stay valid until it expired or a new one was sent: seen
|
|
394
|
+
once (over a shoulder, on a locked screen), it could log in again
|
|
395
|
+
or, from the open session, authorise a sensitive operation."""
|
|
396
|
+
self.add_device('sms', confirmed=True, target='+33612345678')
|
|
397
|
+
with patch(SMS_BACKEND):
|
|
398
|
+
response = self.do_login()
|
|
399
|
+
self.assertRC(response, 200)
|
|
400
|
+
otp_token = self.get_val(response, 'token')
|
|
401
|
+
otp_code = pyotp_hotp(self.get_device('sms'))
|
|
402
|
+
|
|
403
|
+
response = self.client.post('/api/auth/otp/login', dict(
|
|
404
|
+
token=otp_token, otp_code=otp_code, mfa_backend='sms'))
|
|
405
|
+
self.assertRC(response, 200)
|
|
406
|
+
session_token = self.get_val(response, 'token')
|
|
407
|
+
|
|
408
|
+
response = self.client.post('/api/auth/otp/login', dict(
|
|
409
|
+
token=otp_token, otp_code=otp_code, mfa_backend='sms'))
|
|
410
|
+
self.assertRC(response, 422)
|
|
411
|
+
self.assertJE(response, 'otp_code.@0', "Invalid code")
|
|
412
|
+
|
|
413
|
+
self.client.token = session_token
|
|
414
|
+
response = self.client.put(
|
|
415
|
+
'/api/auth/mfa/sms/disable',
|
|
416
|
+
{'otp_code': otp_code, 'mfa_backend': 'sms'})
|
|
417
|
+
self.assertRC(response, 422)
|
|
418
|
+
self.assertJE(response, 'otp_code.@0', "Invalid code")
|
|
419
|
+
self.assertTrue(self.get_device('sms').confirmed)
|
|
420
|
+
|
|
389
421
|
# --- /auth/mfa/challenge endpoint ---
|
|
390
422
|
|
|
391
423
|
def _get_otp_token(self):
|
|
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
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/email_backend/memory_email_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/locale/fr/LC_MESSAGES/django.mo
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/locale/fr/LC_MESSAGES/django.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0002_alter_email_headers.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/migrations/0003_alter_email_options.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/providers/email_django_q_executor.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/templates/emails/base_template.html
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/emails/templates/emails/base_template.txt
RENAMED
|
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
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/fields/minutes_duration_field.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/__init__.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/makeapidoc.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/management/commands/profile.py
RENAMED
|
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
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/operations/__init__.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/migrations/operations/permissions.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/abstract_pfx_base_user.py
RENAMED
|
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
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/models/user_filtered_queryset_mixin.py
RENAMED
|
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
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/media_rest_view_mixin.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/mfa_authentication_views.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/ordered_rest_view_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/date_format.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_count.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_items.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_order.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/list_search.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/media_redirect.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/meta_fields.py
RENAMED
|
File without changes
|
{django_pfx-1.7.6.dev29 → django_pfx-1.7.6.dev33}/pfx/pfxcore/views/parameters/meta_filters.py
RENAMED
|
File without changes
|