wagtail 6.3.2__py3-none-any.whl → 6.4rc1__py3-none-any.whl
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.
- wagtail/__init__.py +1 -1
- wagtail/actions/publish_revision.py +4 -5
- wagtail/admin/auth.py +0 -2
- wagtail/admin/checks.py +1 -1
- wagtail/admin/filters.py +3 -1
- wagtail/admin/forms/account.py +21 -11
- wagtail/admin/forms/collections.py +2 -9
- wagtail/admin/forms/formsets.py +32 -0
- wagtail/admin/forms/pages.py +5 -1
- wagtail/admin/forms/workflows.py +2 -13
- wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/django.po +68 -1
- wagtail/admin/locale/ar/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/djangojs.po +5 -1
- wagtail/admin/locale/en/LC_MESSAGES/django.po +312 -356
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -16
- wagtail/admin/menu.py +0 -13
- wagtail/admin/panels/base.py +2 -2
- wagtail/admin/panels/group.py +4 -1
- wagtail/admin/panels/inline_panel.py +5 -2
- wagtail/admin/panels/model_utils.py +36 -0
- wagtail/admin/panels/page_utils.py +2 -40
- wagtail/admin/panels/signal_handlers.py +0 -2
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
- wagtail/admin/static/wagtailadmin/css/panels/streamfield.css +1 -1
- wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +1 -8
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +7 -0
- wagtail/admin/templates/wagtailadmin/404.html +4 -0
- wagtail/admin/templates/wagtailadmin/chooser/browse.html +2 -1
- wagtail/admin/templates/wagtailadmin/chooser/tables/parent_page_cell.html +1 -1
- wagtail/admin/templates/wagtailadmin/collections/_privacy_switch.html +8 -1
- wagtail/admin/templates/wagtailadmin/generic/confirm_delete.html +15 -9
- wagtail/admin/templates/wagtailadmin/generic/confirm_unpublish.html +21 -25
- wagtail/admin/templates/wagtailadmin/generic/form.html +1 -1
- wagtail/admin/templates/wagtailadmin/generic/preview_error.html +3 -0
- wagtail/admin/templates/wagtailadmin/generic/revisions/compare.html +63 -76
- wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -2
- wagtail/admin/templates/wagtailadmin/pages/edit.html +1 -5
- wagtail/admin/templates/wagtailadmin/panels/inline_panel_child.html +1 -0
- wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_form.html +1 -1
- wagtail/admin/templates/wagtailadmin/permissions/includes/collection_member_permissions_formset.html +6 -22
- wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/header.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +32 -39
- wagtail/admin/templates/wagtailadmin/shared/revisions/confirm_unschedule.html +13 -17
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +15 -3
- wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -1
- wagtail/admin/templates/wagtailadmin/skeleton.html +4 -2
- wagtail/admin/templates/wagtailadmin/workflows/create.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/edit.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_form.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_pages_formset.html +6 -23
- wagtail/admin/templatetags/wagtailadmin_tags.py +12 -0
- wagtail/admin/templatetags/wagtailuserbar.py +2 -3
- wagtail/admin/tests/pages/test_create_page.py +110 -1
- wagtail/admin/tests/pages/test_edit_page.py +3 -2
- wagtail/admin/tests/pages/test_explorer_view.py +18 -0
- wagtail/admin/tests/pages/test_page_usage.py +24 -20
- wagtail/admin/tests/pages/test_preview.py +69 -1
- wagtail/admin/tests/pages/test_revisions.py +40 -6
- wagtail/admin/tests/test_account_management.py +39 -1
- wagtail/admin/tests/test_audit_log.py +4 -2
- wagtail/admin/tests/test_block_preview.py +224 -0
- wagtail/admin/tests/test_edit_handlers.py +23 -6
- wagtail/admin/tests/test_page_chooser.py +50 -3
- wagtail/admin/tests/test_privacy.py +49 -26
- wagtail/admin/tests/test_site_summary.py +15 -10
- wagtail/admin/tests/test_templatetags.py +19 -0
- wagtail/admin/tests/test_userbar.py +82 -1
- wagtail/admin/tests/test_views_generic.py +27 -12
- wagtail/admin/tests/test_workflows.py +69 -0
- wagtail/admin/tests/tests.py +23 -4
- wagtail/admin/tests/ui/test_sidebar.py +1 -1
- wagtail/admin/tests/viewsets/test_model_viewset.py +15 -13
- wagtail/admin/ui/side_panels.py +7 -4
- wagtail/admin/urls/__init__.py +6 -0
- wagtail/admin/urls/pages.py +1 -1
- wagtail/admin/userbar.py +21 -1
- wagtail/admin/views/account.py +5 -0
- wagtail/admin/views/chooser.py +5 -1
- wagtail/admin/views/collections.py +0 -2
- wagtail/admin/views/generic/base.py +20 -10
- wagtail/admin/views/generic/history.py +0 -1
- wagtail/admin/views/generic/models.py +79 -21
- wagtail/admin/views/generic/preview.py +50 -1
- wagtail/admin/views/mixins.py +4 -2
- wagtail/admin/views/pages/bulk_actions/delete.py +11 -23
- wagtail/admin/views/pages/bulk_actions/page_bulk_action.py +17 -0
- wagtail/admin/views/pages/bulk_actions/publish.py +11 -31
- wagtail/admin/views/pages/bulk_actions/unpublish.py +11 -31
- wagtail/admin/views/pages/create.py +1 -0
- wagtail/admin/views/pages/edit.py +38 -30
- wagtail/admin/views/pages/revisions.py +43 -114
- wagtail/admin/views/pages/utils.py +0 -1
- wagtail/admin/views/tags.py +6 -2
- wagtail/admin/views/workflows.py +8 -6
- wagtail/admin/viewsets/model.py +0 -4
- wagtail/admin/viewsets/pages.py +0 -1
- wagtail/admin/widgets/tags.py +1 -0
- wagtail/api/v2/tests/test_documents.py +4 -2
- wagtail/api/v2/tests/test_images.py +4 -2
- wagtail/api/v2/tests/test_pages.py +8 -4
- wagtail/blocks/base.py +59 -1
- wagtail/blocks/field_block.py +6 -0
- wagtail/blocks/list_block.py +4 -0
- wagtail/blocks/static_block.py +3 -0
- wagtail/blocks/stream_block.py +5 -1
- wagtail/blocks/struct_block.py +6 -0
- wagtail/compat.py +16 -0
- wagtail/contrib/forms/forms.py +27 -7
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/contrib/forms/tests/test_models.py +7 -5
- wagtail/contrib/forms/tests/test_views.py +75 -0
- wagtail/contrib/frontend_cache/tasks.py +83 -0
- wagtail/contrib/frontend_cache/tests.py +47 -32
- wagtail/contrib/frontend_cache/utils.py +2 -70
- wagtail/contrib/redirects/base_formats.py +2 -2
- wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.po +3 -0
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +24 -37
- wagtail/contrib/redirects/templates/wagtailredirects/add.html +1 -24
- wagtail/contrib/redirects/templates/wagtailredirects/confirm_delete.html +3 -13
- wagtail/contrib/redirects/tests/test_redirects.py +122 -110
- wagtail/contrib/redirects/tests/test_signal_handlers.py +75 -69
- wagtail/contrib/redirects/urls.py +2 -2
- wagtail/contrib/redirects/views.py +35 -73
- wagtail/contrib/search_promotions/admin_urls.py +10 -3
- wagtail/contrib/search_promotions/forms.py +55 -26
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +44 -54
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/add.html +21 -31
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/confirm_delete.html +3 -12
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/edit.html +11 -34
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotion_form.html +1 -0
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js +2 -1
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +0 -1
- wagtail/contrib/search_promotions/tests.py +814 -13
- wagtail/contrib/search_promotions/views/__init__.py +1 -0
- wagtail/contrib/search_promotions/views/reports.py +56 -0
- wagtail/contrib/search_promotions/views/settings.py +258 -0
- wagtail/contrib/search_promotions/wagtail_hooks.py +12 -1
- wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/ar/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/settings/templates/wagtailsettings/edit.html +1 -5
- wagtail/contrib/settings/tests/generic/test_admin.py +2 -5
- wagtail/contrib/settings/tests/generic/test_register.py +1 -1
- wagtail/contrib/settings/tests/site_specific/test_admin.py +2 -5
- wagtail/contrib/settings/tests/site_specific/test_register.py +1 -1
- wagtail/contrib/settings/views.py +9 -23
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/tests.py +4 -1
- wagtail/contrib/typed_table_block/blocks.py +3 -0
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
- wagtail/contrib/typed_table_block/tests.py +33 -0
- wagtail/documents/locale/en/LC_MESSAGES/django.po +26 -26
- wagtail/documents/migrations/0011_add_choose_permissions.py +1 -0
- wagtail/documents/models.py +1 -0
- wagtail/documents/signal_handlers.py +6 -2
- wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
- wagtail/documents/templates/wagtaildocs/documents/edit.html +1 -3
- wagtail/documents/templates/wagtaildocs/multiple/add.html +7 -1
- wagtail/documents/tests/test_admin_views.py +74 -33
- wagtail/documents/tests/test_views.py +21 -12
- wagtail/documents/views/chooser.py +1 -0
- wagtail/documents/views/documents.py +1 -2
- wagtail/documents/views/multiple.py +0 -1
- wagtail/documents/views/serve.py +9 -2
- wagtail/documents/wagtail_hooks.py +6 -1
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/oembed_providers.py +0 -64
- wagtail/fields.py +3 -0
- wagtail/images/apps.py +2 -1
- wagtail/images/blocks.py +6 -2
- wagtail/images/forms.py +40 -3
- wagtail/images/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/ar/LC_MESSAGES/django.po +4 -0
- wagtail/images/locale/en/LC_MESSAGES/django.po +49 -49
- wagtail/images/migrations/0023_add_choose_permissions.py +1 -0
- wagtail/images/rich_text/contentstate.py +1 -0
- wagtail/images/rich_text/editor_html.py +1 -0
- wagtail/images/signal_handlers.py +17 -10
- wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
- wagtail/images/static/wagtailimages/js/image-block.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
- wagtail/images/tasks.py +18 -0
- wagtail/images/templates/wagtailimages/images/edit.html +1 -3
- wagtail/images/templates/wagtailimages/images/url_generator.html +1 -1
- wagtail/images/templates/wagtailimages/multiple/add.html +7 -2
- wagtail/images/templates/wagtailimages/widgets/image_chooser.html +1 -1
- wagtail/images/tests/test_admin_views.py +53 -29
- wagtail/images/tests/test_blocks.py +3 -2
- wagtail/images/tests/test_models.py +12 -10
- wagtail/images/tests/tests.py +10 -0
- wagtail/images/views/chooser.py +1 -0
- wagtail/images/views/images.py +1 -3
- wagtail/images/views/multiple.py +0 -1
- wagtail/images/views/serve.py +18 -2
- wagtail/images/widgets.py +3 -0
- wagtail/locale/en/LC_MESSAGES/django.po +228 -216
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/management/commands/publish_scheduled.py +1 -1
- wagtail/migrations/0087_alter_grouppagepermission_unique_together_and_more.py +16 -8
- wagtail/models/__init__.py +300 -119
- wagtail/models/i18n.py +2 -2
- wagtail/models/panels.py +37 -0
- wagtail/models/sites.py +7 -6
- wagtail/permission_policies/pages.py +2 -2
- wagtail/project_template/project_name/settings/base.py +4 -0
- wagtail/project_template/requirements.txt +1 -1
- wagtail/query.py +145 -0
- wagtail/search/backends/database/mysql/mysql.py +25 -17
- wagtail/search/backends/database/postgres/postgres.py +44 -83
- wagtail/search/backends/database/sqlite/sqlite.py +25 -17
- wagtail/search/backends/elasticsearch7.py +4 -0
- wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/search/query.py +8 -2
- wagtail/search/signal_handlers.py +6 -9
- wagtail/search/tasks.py +10 -0
- wagtail/search/tests/test_elasticsearch7_backend.py +21 -0
- wagtail/search/tests/test_index_functions.py +10 -6
- wagtail/search/tests/test_postgres_backend.py +0 -14
- wagtail/signal_handlers.py +5 -20
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -13
- wagtail/snippets/tests/test_preview.py +5 -0
- wagtail/snippets/tests/test_snippets.py +100 -45
- wagtail/snippets/tests/test_usage.py +29 -24
- wagtail/snippets/tests/test_viewset.py +1 -1
- wagtail/snippets/views/snippets.py +0 -12
- wagtail/tasks.py +41 -0
- wagtail/templates/wagtailcore/shared/block_preview.html +29 -0
- wagtail/test/earlypage/__init__.py +0 -0
- wagtail/test/earlypage/migrations/0001_initial.py +37 -0
- wagtail/test/earlypage/migrations/__init__.py +0 -0
- wagtail/test/earlypage/models.py +14 -0
- wagtail/test/settings.py +3 -0
- wagtail/test/testapp/fixtures/test.json +7 -0
- wagtail/test/testapp/fixtures/test_specific.json +6 -3
- wagtail/test/testapp/models.py +58 -44
- wagtail/test/testapp/templates/tests/custom_block_preview.html +16 -0
- wagtail/test/testapp/templates/tests/static_block_preview.html +5 -0
- wagtail/test/testapp/wagtail_hooks.py +9 -0
- wagtail/tests/test_blocks.py +189 -2
- wagtail/tests/test_hooks.py +166 -1
- wagtail/tests/test_management_commands.py +54 -13
- wagtail/tests/test_page_allowed_http_methods.py +32 -0
- wagtail/tests/test_page_model.py +68 -0
- wagtail/tests/test_page_privacy.py +10 -0
- wagtail/tests/test_page_queryset.py +79 -0
- wagtail/tests/test_reference_index.py +84 -75
- wagtail/tests/test_streamfield.py +30 -0
- wagtail/tests/test_utils.py +61 -0
- wagtail/users/forms.py +2 -9
- wagtail/users/locale/en/LC_MESSAGES/django.po +17 -17
- wagtail/users/templates/wagtailusers/groups/create.html +0 -5
- wagtail/users/templates/wagtailusers/groups/includes/page_permissions_form.html +1 -1
- wagtail/users/templates/wagtailusers/groups/includes/page_permissions_formset.html +6 -6
- wagtail/users/tests/test_admin_views.py +96 -4
- wagtail/users/tests/test_utils.py +76 -0
- wagtail/users/utils.py +43 -11
- wagtail/utils/setup.py +2 -2
- wagtail/utils/templates.py +26 -0
- wagtail/utils/widgets.py +1 -0
- wagtail/views.py +9 -1
- wagtail/wagtail_hooks.py +67 -29
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/METADATA +2 -2
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/RECORD +289 -276
- wagtail/admin/static/wagtailadmin/js/expanding-formset.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/rangy-core.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/uuidv4.min.js +0 -1
- wagtail/contrib/search_promotions/views.py +0 -323
- wagtail/images/static/wagtailimages/js/vendor/canvas-to-blob.min.js +0 -1
- wagtail/users/static/wagtailusers/js/group-form.js +0 -1
- wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -3
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/LICENSE +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/WHEEL +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-6.3.2.dist-info → wagtail-6.4rc1.dist-info}/top_level.txt +0 -0
wagtail/tests/test_utils.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
+
import os
|
|
2
3
|
import pickle
|
|
4
|
+
import tempfile
|
|
3
5
|
import unittest
|
|
6
|
+
import warnings
|
|
4
7
|
from io import BytesIO
|
|
5
8
|
from pathlib import Path
|
|
6
9
|
|
|
10
|
+
from django.conf import settings
|
|
7
11
|
from django.contrib.contenttypes.models import ContentType
|
|
8
12
|
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
|
9
13
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
@@ -27,7 +31,9 @@ from wagtail.coreutils import (
|
|
|
27
31
|
string_to_ascii,
|
|
28
32
|
)
|
|
29
33
|
from wagtail.models import Page, Site
|
|
34
|
+
from wagtail.utils.deprecation import RemovedInWagtail70Warning
|
|
30
35
|
from wagtail.utils.file import hash_filelike
|
|
36
|
+
from wagtail.utils.templates import template_is_overridden
|
|
31
37
|
from wagtail.utils.utils import deep_update, flatten_choices
|
|
32
38
|
from wagtail.utils.version import get_main_version
|
|
33
39
|
|
|
@@ -578,6 +584,41 @@ class HashFileLikeTestCase(SimpleTestCase):
|
|
|
578
584
|
)
|
|
579
585
|
|
|
580
586
|
|
|
587
|
+
class TestTemplateIsOverridden(SimpleTestCase):
|
|
588
|
+
def setUp(self):
|
|
589
|
+
template_is_overridden.cache_clear()
|
|
590
|
+
|
|
591
|
+
def test_template_is_overridden_false(self):
|
|
592
|
+
self.assertIs(
|
|
593
|
+
template_is_overridden(
|
|
594
|
+
"wagtailcore/shared/block_preview.html",
|
|
595
|
+
"templates",
|
|
596
|
+
),
|
|
597
|
+
False,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
def test_template_is_overridden_true(self):
|
|
601
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
602
|
+
path = os.path.join(temp_dir, "wagtailcore/shared")
|
|
603
|
+
os.makedirs(path, exist_ok=True)
|
|
604
|
+
with open(os.path.join(path, "block_preview.html"), "w") as f:
|
|
605
|
+
f.write("Custom file")
|
|
606
|
+
|
|
607
|
+
with self.settings(
|
|
608
|
+
TEMPLATES=[
|
|
609
|
+
{**settings.TEMPLATES[0], "DIRS": [temp_dir], "NAME": "tmp"},
|
|
610
|
+
*settings.TEMPLATES,
|
|
611
|
+
]
|
|
612
|
+
):
|
|
613
|
+
self.assertIs(
|
|
614
|
+
template_is_overridden(
|
|
615
|
+
"wagtailcore/shared/block_preview.html",
|
|
616
|
+
"templates",
|
|
617
|
+
),
|
|
618
|
+
True,
|
|
619
|
+
)
|
|
620
|
+
|
|
621
|
+
|
|
581
622
|
class TestVersion(SimpleTestCase):
|
|
582
623
|
def test_get_main_version(self):
|
|
583
624
|
cases = [
|
|
@@ -616,3 +657,23 @@ class TestFlattenChoices(SimpleTestCase):
|
|
|
616
657
|
"unknown": "Unknown",
|
|
617
658
|
},
|
|
618
659
|
)
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
class TestWidgetWithScript(TestCase):
|
|
663
|
+
def test_deprecation(self):
|
|
664
|
+
message = "The usage of `WidgetWithScript` hook is deprecated. Use external scripts instead."
|
|
665
|
+
|
|
666
|
+
with unittest.mock.patch("warnings.warn", wraps=warnings.warn) as warn_mock:
|
|
667
|
+
with self.assertWarnsMessage(RemovedInWagtail70Warning, message):
|
|
668
|
+
from wagtail.utils.widgets import WidgetWithScript
|
|
669
|
+
|
|
670
|
+
class MyWidget(WidgetWithScript):
|
|
671
|
+
pass
|
|
672
|
+
|
|
673
|
+
# Make sure warn was called with stacklevel=3, so the actual caller
|
|
674
|
+
# that imports WidgetWithScript is shown in the warning message
|
|
675
|
+
warn_mock.assert_called_with(
|
|
676
|
+
message,
|
|
677
|
+
category=RemovedInWagtail70Warning,
|
|
678
|
+
stacklevel=3,
|
|
679
|
+
)
|
wagtail/users/forms.py
CHANGED
|
@@ -15,6 +15,7 @@ from django.utils.html import mark_safe
|
|
|
15
15
|
from django.utils.translation import gettext_lazy as _
|
|
16
16
|
|
|
17
17
|
from wagtail import hooks
|
|
18
|
+
from wagtail.admin.forms.formsets import BaseFormSetMixin
|
|
18
19
|
from wagtail.admin.widgets import AdminPageChooser
|
|
19
20
|
from wagtail.models import (
|
|
20
21
|
PAGE_PERMISSION_CODENAMES,
|
|
@@ -319,7 +320,7 @@ class PagePermissionsForm(forms.Form):
|
|
|
319
320
|
)
|
|
320
321
|
|
|
321
322
|
|
|
322
|
-
class BaseGroupPagePermissionFormSet(forms.BaseFormSet):
|
|
323
|
+
class BaseGroupPagePermissionFormSet(BaseFormSetMixin, forms.BaseFormSet):
|
|
323
324
|
# defined here for easy access from templates
|
|
324
325
|
permission_types = PAGE_PERMISSION_TYPES
|
|
325
326
|
|
|
@@ -350,14 +351,6 @@ class BaseGroupPagePermissionFormSet(forms.BaseFormSet):
|
|
|
350
351
|
)
|
|
351
352
|
|
|
352
353
|
super().__init__(data, files, initial=initial_data, prefix=prefix)
|
|
353
|
-
for form in self.forms:
|
|
354
|
-
form.fields["DELETE"].widget = forms.HiddenInput()
|
|
355
|
-
|
|
356
|
-
@property
|
|
357
|
-
def empty_form(self):
|
|
358
|
-
empty_form = super().empty_form
|
|
359
|
-
empty_form.fields["DELETE"].widget = forms.HiddenInput()
|
|
360
|
-
return empty_form
|
|
361
354
|
|
|
362
355
|
def clean(self):
|
|
363
356
|
"""Checks that no two forms refer to the same page object"""
|
|
@@ -8,7 +8,7 @@ msgid ""
|
|
|
8
8
|
msgstr ""
|
|
9
9
|
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
10
|
"Report-Msgid-Bugs-To: \n"
|
|
11
|
-
"POT-Creation-Date:
|
|
11
|
+
"POT-Creation-Date: 2025-01-20 17:59+0000\n"
|
|
12
12
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
13
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
14
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
@@ -22,63 +22,63 @@ msgstr ""
|
|
|
22
22
|
msgid "Wagtail users"
|
|
23
23
|
msgstr ""
|
|
24
24
|
|
|
25
|
-
#: forms.py:
|
|
25
|
+
#: forms.py:56
|
|
26
26
|
msgid "Required. Letters, digits and @/./+/-/_ only."
|
|
27
27
|
msgstr ""
|
|
28
28
|
|
|
29
|
-
#: forms.py:
|
|
29
|
+
#: forms.py:61
|
|
30
30
|
msgid "This value may contain only letters, numbers and @/./+/-/_ characters."
|
|
31
31
|
msgstr ""
|
|
32
32
|
|
|
33
|
-
#: forms.py:
|
|
33
|
+
#: forms.py:87
|
|
34
34
|
msgid "A user with that username already exists."
|
|
35
35
|
msgstr ""
|
|
36
36
|
|
|
37
|
-
#: forms.py:
|
|
37
|
+
#: forms.py:88
|
|
38
38
|
msgid "The two password fields didn't match."
|
|
39
39
|
msgstr ""
|
|
40
40
|
|
|
41
|
-
#: forms.py:
|
|
41
|
+
#: forms.py:91
|
|
42
42
|
msgid "Email"
|
|
43
43
|
msgstr ""
|
|
44
44
|
|
|
45
|
-
#: forms.py:
|
|
45
|
+
#: forms.py:92
|
|
46
46
|
msgid "First Name"
|
|
47
47
|
msgstr ""
|
|
48
48
|
|
|
49
|
-
#: forms.py:
|
|
49
|
+
#: forms.py:93
|
|
50
50
|
msgid "Last Name"
|
|
51
51
|
msgstr ""
|
|
52
52
|
|
|
53
|
-
#: forms.py:
|
|
53
|
+
#: forms.py:96
|
|
54
54
|
msgid "Password"
|
|
55
55
|
msgstr ""
|
|
56
56
|
|
|
57
|
-
#: forms.py:
|
|
57
|
+
#: forms.py:99
|
|
58
58
|
msgid "Leave blank if not changing."
|
|
59
59
|
msgstr ""
|
|
60
60
|
|
|
61
|
-
#: forms.py:
|
|
61
|
+
#: forms.py:103
|
|
62
62
|
msgid "Password confirmation"
|
|
63
63
|
msgstr ""
|
|
64
64
|
|
|
65
|
-
#: forms.py:
|
|
65
|
+
#: forms.py:106
|
|
66
66
|
msgid "Enter the same password as above, for verification."
|
|
67
67
|
msgstr ""
|
|
68
68
|
|
|
69
|
-
#: forms.py:
|
|
69
|
+
#: forms.py:111 forms.py:248 views/users.py:110
|
|
70
70
|
msgid "Administrator"
|
|
71
71
|
msgstr ""
|
|
72
72
|
|
|
73
|
-
#: forms.py:
|
|
73
|
+
#: forms.py:114 forms.py:250
|
|
74
74
|
msgid "Administrators have full access to manage any object or setting."
|
|
75
75
|
msgstr ""
|
|
76
76
|
|
|
77
|
-
#: forms.py:
|
|
77
|
+
#: forms.py:244
|
|
78
78
|
msgid "A group with that name already exists."
|
|
79
79
|
msgstr ""
|
|
80
80
|
|
|
81
|
-
#: forms.py:
|
|
81
|
+
#: forms.py:371
|
|
82
82
|
msgid "You cannot have multiple permission records for the same page."
|
|
83
83
|
msgstr ""
|
|
84
84
|
|
|
@@ -400,7 +400,7 @@ msgstr ""
|
|
|
400
400
|
msgid "Can view"
|
|
401
401
|
msgstr ""
|
|
402
402
|
|
|
403
|
-
#: utils.py:
|
|
403
|
+
#: utils.py:85
|
|
404
404
|
#, python-format
|
|
405
405
|
msgid "user %(id)s (deleted)"
|
|
406
406
|
msgstr ""
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
{% endfor %}
|
|
11
11
|
|
|
12
12
|
<td>
|
|
13
|
-
<button class="button button-small no" type="button" id="{{ form.DELETE.id_for_label }}-button">{% trans "Delete" %}</button>
|
|
13
|
+
<button class="button button-small no" type="button" id="{{ form.DELETE.id_for_label }}-button" data-action="w-formset#delete">{% trans "Delete" %}</button>
|
|
14
14
|
</td>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{% load i18n wagtailadmin_tags %}
|
|
2
2
|
|
|
3
3
|
{% trans "Page permissions" as heading %}
|
|
4
|
-
{% panel id="page-permissions" heading=heading icon="folder-open-inverse" %}
|
|
4
|
+
{% panel id="page-permissions" heading=heading icon="folder-open-inverse" attrs=formset.attrs %}
|
|
5
5
|
|
|
6
6
|
{{ formset.management_form }}
|
|
7
7
|
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
{% endfor %}
|
|
28
28
|
</tr>
|
|
29
29
|
</thead>
|
|
30
|
-
<tbody id="id_{{ formset.prefix }}-FORMS">
|
|
30
|
+
<tbody id="id_{{ formset.prefix }}-FORMS" data-w-formset-target="forms">
|
|
31
31
|
{% for form in formset.forms %}
|
|
32
|
-
<tr id="inline_child_{{ form.prefix }}"{% if form.DELETE.value %}
|
|
32
|
+
<tr id="inline_child_{{ form.prefix }}"{% if form.DELETE.value %} hidden data-w-formset-target="deleted"{% else %}data-w-formset-target="child"{% endif %}>
|
|
33
33
|
{% if form.non_field_errors %}
|
|
34
34
|
<p class="error-message">
|
|
35
35
|
{% for error in form.non_field_errors %}
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
</tbody>
|
|
44
44
|
</table>
|
|
45
45
|
|
|
46
|
-
<template id="id_{{ formset.prefix }}-EMPTY_FORM_TEMPLATE">
|
|
47
|
-
<tr id="inline_child_{{ formset.empty_form.prefix }}">
|
|
46
|
+
<template id="id_{{ formset.prefix }}-EMPTY_FORM_TEMPLATE" data-w-formset-target="template">
|
|
47
|
+
<tr id="inline_child_{{ formset.empty_form.prefix }}" data-w-formset-target="child">
|
|
48
48
|
{% include "wagtailusers/groups/includes/page_permissions_form.html" with form=formset.empty_form only %}
|
|
49
49
|
</tr>
|
|
50
50
|
</template>
|
|
51
51
|
|
|
52
52
|
<p class="add">
|
|
53
|
-
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button">{% icon name="plus" wrapped=1 %}{% trans "Add a page permission" %}</button>
|
|
53
|
+
<button class="button bicolor button--icon" id="id_{{ formset.prefix }}-ADD" value="Add" type="button" data-action="w-formset#add">{% icon name="plus" wrapped=1 %}{% trans "Add a page permission" %}</button>
|
|
54
54
|
</p>
|
|
55
55
|
|
|
56
56
|
{% endpanel %}
|
|
@@ -1735,9 +1735,7 @@ class TestGroupCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
1735
1735
|
)
|
|
1736
1736
|
# Should contain the JS from the form and the template include
|
|
1737
1737
|
page_chooser_js = versioned_static("wagtailadmin/js/page-chooser.js")
|
|
1738
|
-
group_form_js = versioned_static("wagtailusers/js/group-form.js")
|
|
1739
1738
|
self.assertContains(response, page_chooser_js)
|
|
1740
|
-
self.assertContains(response, group_form_js)
|
|
1741
1739
|
|
|
1742
1740
|
def test_num_queries(self):
|
|
1743
1741
|
# Warm up the cache
|
|
@@ -2009,6 +2007,49 @@ class TestGroupCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2009
2007
|
custom_label.get_text(strip=True), "Can sync roadmap items from GitHub"
|
|
2010
2008
|
)
|
|
2011
2009
|
|
|
2010
|
+
def test_formset_data_attributes(self):
|
|
2011
|
+
response = self.get()
|
|
2012
|
+
soup = self.get_soup(response.content)
|
|
2013
|
+
|
|
2014
|
+
panel = soup.find(id="page-permissions-section")
|
|
2015
|
+
self.assertIn("w-formset", panel.attrs["data-controller"])
|
|
2016
|
+
self.assertEqual(
|
|
2017
|
+
"totalFormsInput",
|
|
2018
|
+
panel.find(id="id_page_permissions-TOTAL_FORMS").attrs[
|
|
2019
|
+
"data-w-formset-target"
|
|
2020
|
+
],
|
|
2021
|
+
)
|
|
2022
|
+
self.assertEqual(
|
|
2023
|
+
"template",
|
|
2024
|
+
panel.find("template").attrs["data-w-formset-target"],
|
|
2025
|
+
)
|
|
2026
|
+
|
|
2027
|
+
self.assertEqual(
|
|
2028
|
+
"forms",
|
|
2029
|
+
panel.find("table").find("tbody").attrs["data-w-formset-target"],
|
|
2030
|
+
)
|
|
2031
|
+
|
|
2032
|
+
# Other panels are rendered with different formset classes, test one of them
|
|
2033
|
+
|
|
2034
|
+
panel = soup.find(id="collection-management-permissions-section")
|
|
2035
|
+
self.assertIn("w-formset", panel.attrs["data-controller"])
|
|
2036
|
+
|
|
2037
|
+
self.assertEqual(
|
|
2038
|
+
"totalFormsInput",
|
|
2039
|
+
panel.find(id="id_collection_permissions-TOTAL_FORMS").attrs[
|
|
2040
|
+
"data-w-formset-target"
|
|
2041
|
+
],
|
|
2042
|
+
)
|
|
2043
|
+
self.assertEqual(
|
|
2044
|
+
"template",
|
|
2045
|
+
panel.find("template").attrs["data-w-formset-target"],
|
|
2046
|
+
)
|
|
2047
|
+
|
|
2048
|
+
self.assertEqual(
|
|
2049
|
+
"forms",
|
|
2050
|
+
panel.find("table").find("tbody").attrs["data-w-formset-target"],
|
|
2051
|
+
)
|
|
2052
|
+
|
|
2012
2053
|
|
|
2013
2054
|
class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
2014
2055
|
def setUp(self):
|
|
@@ -2109,9 +2150,7 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2109
2150
|
)
|
|
2110
2151
|
# Should contain the JS from the form and the template include
|
|
2111
2152
|
page_chooser_js = versioned_static("wagtailadmin/js/page-chooser.js")
|
|
2112
|
-
group_form_js = versioned_static("wagtailusers/js/group-form.js")
|
|
2113
2153
|
self.assertContains(response, page_chooser_js)
|
|
2114
|
-
self.assertContains(response, group_form_js)
|
|
2115
2154
|
|
|
2116
2155
|
soup = self.get_soup(response.content)
|
|
2117
2156
|
header = soup.select_one(".w-slim-header")
|
|
@@ -2608,6 +2647,59 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
2608
2647
|
self.assertGreaterEqual(len(toggle_add_items), 30)
|
|
2609
2648
|
self.assertEqual(toggle_add_items[0]["data-action"], "w-bulk#toggle")
|
|
2610
2649
|
|
|
2650
|
+
def test_formset_data_attributes(self):
|
|
2651
|
+
response = self.get()
|
|
2652
|
+
soup = self.get_soup(response.content)
|
|
2653
|
+
|
|
2654
|
+
panel = soup.find(id="page-permissions-section")
|
|
2655
|
+
self.assertIn("w-formset", panel.attrs["data-controller"])
|
|
2656
|
+
self.assertEqual(
|
|
2657
|
+
"totalFormsInput",
|
|
2658
|
+
panel.find(id="id_page_permissions-TOTAL_FORMS").attrs[
|
|
2659
|
+
"data-w-formset-target"
|
|
2660
|
+
],
|
|
2661
|
+
)
|
|
2662
|
+
self.assertEqual(
|
|
2663
|
+
"template",
|
|
2664
|
+
panel.find("template").attrs["data-w-formset-target"],
|
|
2665
|
+
)
|
|
2666
|
+
|
|
2667
|
+
tbody = panel.find("table").find("tbody")
|
|
2668
|
+
self.assertEqual(
|
|
2669
|
+
"forms",
|
|
2670
|
+
tbody.attrs["data-w-formset-target"],
|
|
2671
|
+
)
|
|
2672
|
+
|
|
2673
|
+
row = tbody.find("tr")
|
|
2674
|
+
self.assertEqual(
|
|
2675
|
+
"child",
|
|
2676
|
+
row.attrs["data-w-formset-target"],
|
|
2677
|
+
)
|
|
2678
|
+
self.assertEqual(
|
|
2679
|
+
"deleteInput",
|
|
2680
|
+
row.find(id="id_page_permissions-0-DELETE").attrs["data-w-formset-target"],
|
|
2681
|
+
)
|
|
2682
|
+
|
|
2683
|
+
# Other panels are rendered with different formset classes, test one of them
|
|
2684
|
+
|
|
2685
|
+
panel = soup.find(id="collection-management-permissions-section")
|
|
2686
|
+
self.assertIn("w-formset", panel.attrs["data-controller"])
|
|
2687
|
+
|
|
2688
|
+
self.assertEqual(
|
|
2689
|
+
"totalFormsInput",
|
|
2690
|
+
panel.find(id="id_collection_permissions-TOTAL_FORMS").attrs[
|
|
2691
|
+
"data-w-formset-target"
|
|
2692
|
+
],
|
|
2693
|
+
)
|
|
2694
|
+
self.assertEqual(
|
|
2695
|
+
"template",
|
|
2696
|
+
panel.find("template").attrs["data-w-formset-target"],
|
|
2697
|
+
)
|
|
2698
|
+
self.assertEqual(
|
|
2699
|
+
"forms",
|
|
2700
|
+
panel.find("table").find("tbody").attrs["data-w-formset-target"],
|
|
2701
|
+
)
|
|
2702
|
+
|
|
2611
2703
|
|
|
2612
2704
|
class TestGroupHistoryView(WagtailTestUtils, TestCase):
|
|
2613
2705
|
# More thorough tests are in test_model_viewset
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from django.test import TestCase, override_settings
|
|
2
|
+
|
|
3
|
+
from wagtail.users.utils import get_gravatar_url
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestGravatar(TestCase):
|
|
7
|
+
def test_gravatar_default(self):
|
|
8
|
+
"""Test with the default settings"""
|
|
9
|
+
self.assertEqual(
|
|
10
|
+
get_gravatar_url("something@example.com"),
|
|
11
|
+
"//www.gravatar.com/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
def test_gravatar_custom_size(self):
|
|
15
|
+
"""Test with a custom size (note that the size will be doubled)"""
|
|
16
|
+
self.assertEqual(
|
|
17
|
+
get_gravatar_url("something@example.com", size=100),
|
|
18
|
+
"//www.gravatar.com/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=200",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
@override_settings(
|
|
22
|
+
WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?d=robohash&s=200"
|
|
23
|
+
)
|
|
24
|
+
def test_gravatar_params_that_overlap(self):
|
|
25
|
+
"""
|
|
26
|
+
Test with params that overlap with default s (size) and d (default_image)
|
|
27
|
+
Also test the `s` is not overridden by the provider URL's query parameters.
|
|
28
|
+
"""
|
|
29
|
+
self.assertEqual(
|
|
30
|
+
get_gravatar_url("something@example.com", size=80),
|
|
31
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=robohash&s=160",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?f=y")
|
|
35
|
+
def test_gravatar_params_that_dont_overlap(self):
|
|
36
|
+
"""Test with params that don't default `s (size)` and `d (default_image)`"""
|
|
37
|
+
self.assertEqual(
|
|
38
|
+
get_gravatar_url("something@example.com"),
|
|
39
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&f=y&s=100",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@override_settings(
|
|
43
|
+
WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?d=robohash&f=y"
|
|
44
|
+
)
|
|
45
|
+
def test_gravatar_query_params_override_default_params(self):
|
|
46
|
+
"""Test that query parameters of `WAGTAIL_GRAVATAR_PROVIDER_URL` override default_params"""
|
|
47
|
+
self.assertEqual(
|
|
48
|
+
get_gravatar_url(
|
|
49
|
+
"something@example.com", default_params={"d": "monsterid"}
|
|
50
|
+
),
|
|
51
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=robohash&f=y&s=100",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar/")
|
|
55
|
+
def test_gravatar_trailing_slash(self):
|
|
56
|
+
"""Test with a trailing slash in the URL"""
|
|
57
|
+
self.assertEqual(
|
|
58
|
+
get_gravatar_url("something@example.com"),
|
|
59
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar")
|
|
63
|
+
def test_gravatar_no_trailing_slash(self):
|
|
64
|
+
"""Test with no trailing slash in the URL"""
|
|
65
|
+
self.assertEqual(
|
|
66
|
+
get_gravatar_url("something@example.com"),
|
|
67
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?")
|
|
71
|
+
def test_gravatar_trailing_question_mark(self):
|
|
72
|
+
"""Test with a trailing question mark in the URL"""
|
|
73
|
+
self.assertEqual(
|
|
74
|
+
get_gravatar_url("something@example.com"),
|
|
75
|
+
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
|
|
76
|
+
)
|
wagtail/users/utils.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from urllib.parse import parse_qs, urlparse, urlunparse
|
|
2
|
+
|
|
1
3
|
from django.conf import settings
|
|
2
4
|
from django.utils.http import urlencode
|
|
3
5
|
from django.utils.translation import gettext_lazy as _
|
|
@@ -25,11 +27,29 @@ def user_can_delete_user(current_user, user_to_delete):
|
|
|
25
27
|
return True
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
def get_gravatar_url(email, size=50):
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
def get_gravatar_url(email, size=50, default_params={"d": "mp"}):
|
|
31
|
+
"""
|
|
32
|
+
See https://gravatar.com/site/implement/images/ for Gravatar image options.
|
|
33
|
+
|
|
34
|
+
Example usage:
|
|
35
|
+
|
|
36
|
+
.. code-block:: python
|
|
37
|
+
|
|
38
|
+
# Basic usage
|
|
39
|
+
gravatar_url = get_gravatar_url('user@example.com')
|
|
40
|
+
|
|
41
|
+
# Customize size and default image
|
|
42
|
+
gravatar_url = get_gravatar_url(
|
|
43
|
+
'user@example.com',
|
|
44
|
+
size=100,
|
|
45
|
+
default_params={'d': 'robohash', 'f': 'y'}
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
Note:
|
|
49
|
+
If any parameter in ``default_params`` also exists in the provider URL,
|
|
50
|
+
it will be overridden by the provider URL's query parameter.
|
|
51
|
+
"""
|
|
52
|
+
|
|
33
53
|
gravatar_provider_url = getattr(
|
|
34
54
|
settings, "WAGTAIL_GRAVATAR_PROVIDER_URL", "//www.gravatar.com/avatar"
|
|
35
55
|
)
|
|
@@ -37,14 +57,26 @@ def get_gravatar_url(email, size=50):
|
|
|
37
57
|
if (not email) or (gravatar_provider_url is None):
|
|
38
58
|
return None
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
parsed_url = urlparse(gravatar_provider_url)
|
|
61
|
+
|
|
62
|
+
params = {
|
|
63
|
+
**default_params,
|
|
64
|
+
**(parse_qs(parsed_url.query or "")),
|
|
65
|
+
# requested at retina size by default and scaled down at point of use with css
|
|
66
|
+
"s": int(size) * 2,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
email_hash = safe_md5(
|
|
70
|
+
email.lower().encode("utf-8"), usedforsecurity=False
|
|
71
|
+
).hexdigest()
|
|
72
|
+
|
|
73
|
+
parsed_url = parsed_url._replace(
|
|
74
|
+
path=f"{parsed_url.path.rstrip('/')}/{email_hash}",
|
|
75
|
+
query=urlencode(params, doseq=True),
|
|
46
76
|
)
|
|
47
77
|
|
|
78
|
+
gravatar_url = urlunparse(parsed_url)
|
|
79
|
+
|
|
48
80
|
return gravatar_url
|
|
49
81
|
|
|
50
82
|
|
wagtail/utils/setup.py
CHANGED
|
@@ -29,10 +29,10 @@ class assets_mixin:
|
|
|
29
29
|
Writes the current Wagtail version number into package.json
|
|
30
30
|
"""
|
|
31
31
|
path = os.path.join(".", "client", "package.json")
|
|
32
|
-
input_file = open(path)
|
|
33
32
|
|
|
34
33
|
try:
|
|
35
|
-
|
|
34
|
+
with open(path, "r") as f:
|
|
35
|
+
package = json.loads(f.read())
|
|
36
36
|
except ValueError as e:
|
|
37
37
|
print("Unable to read " + path + " " + e) # noqa: T201
|
|
38
38
|
raise SystemExit(1)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from django.template import TemplateDoesNotExist
|
|
5
|
+
from django.template.loader import select_template
|
|
6
|
+
|
|
7
|
+
import wagtail
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@lru_cache(maxsize=None)
|
|
11
|
+
def template_is_overridden(template_name: str, expected_location: str) -> bool:
|
|
12
|
+
"""
|
|
13
|
+
Check if a template has been overridden.
|
|
14
|
+
|
|
15
|
+
A template is overridden if the resolved template file is different from the
|
|
16
|
+
expected location within the `wagtail` package directory.
|
|
17
|
+
"""
|
|
18
|
+
try:
|
|
19
|
+
template = select_template([template_name])
|
|
20
|
+
except TemplateDoesNotExist:
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
root = Path(wagtail.__file__).resolve().parent
|
|
24
|
+
path = str(root / expected_location / template_name)
|
|
25
|
+
|
|
26
|
+
return template.origin.name != path
|
wagtail/utils/widgets.py
CHANGED
wagtail/views.py
CHANGED
|
@@ -9,6 +9,10 @@ from wagtail.forms import PasswordViewRestrictionForm
|
|
|
9
9
|
from wagtail.models import Page, PageViewRestriction
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
def serve_chain(page, request, args, kwargs):
|
|
13
|
+
return page.serve(request, *args, **kwargs)
|
|
14
|
+
|
|
15
|
+
|
|
12
16
|
def serve(request, path):
|
|
13
17
|
route_result = Page.route_for_request(request, path)
|
|
14
18
|
if route_result is None:
|
|
@@ -16,12 +20,16 @@ def serve(request, path):
|
|
|
16
20
|
else:
|
|
17
21
|
page, args, kwargs = route_result
|
|
18
22
|
|
|
23
|
+
on_serve_chain = serve_chain
|
|
24
|
+
for fn in reversed(hooks.get_hooks("on_serve_page")):
|
|
25
|
+
on_serve_chain = fn(on_serve_chain)
|
|
26
|
+
|
|
19
27
|
for fn in hooks.get_hooks("before_serve_page"):
|
|
20
28
|
result = fn(page, request, args, kwargs)
|
|
21
29
|
if isinstance(result, HttpResponse):
|
|
22
30
|
return result
|
|
23
31
|
|
|
24
|
-
return page
|
|
32
|
+
return on_serve_chain(page, request, args, kwargs)
|
|
25
33
|
|
|
26
34
|
|
|
27
35
|
def authenticate_with_password(request, page_view_restriction_id, page_id):
|