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
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
2
|
from django.db import transaction
|
|
3
|
-
from django.db.models.signals import post_delete,
|
|
3
|
+
from django.db.models.signals import post_delete, post_save
|
|
4
4
|
|
|
5
5
|
from wagtail.images import get_image_model
|
|
6
|
+
from wagtail.tasks import delete_file_from_storage_task
|
|
7
|
+
|
|
8
|
+
from .tasks import set_image_focal_point_task
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
def post_delete_file_cleanup(instance, **kwargs):
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
transaction.on_commit(
|
|
13
|
+
lambda: delete_file_from_storage_task.enqueue(
|
|
14
|
+
instance.file.storage.deconstruct(), instance.file.name
|
|
15
|
+
)
|
|
16
|
+
)
|
|
11
17
|
|
|
12
18
|
|
|
13
19
|
def post_delete_purge_rendition_cache(instance, **kwargs):
|
|
14
20
|
instance.purge_from_cache()
|
|
15
21
|
|
|
16
22
|
|
|
17
|
-
def
|
|
23
|
+
def post_save_image_feature_detection(instance, **kwargs):
|
|
18
24
|
if getattr(settings, "WAGTAILIMAGES_FEATURE_DETECTION_ENABLED", False):
|
|
19
25
|
# Make sure the image is not from a fixture
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
instance.
|
|
26
|
+
# and the image doesn't already have a focal point
|
|
27
|
+
if kwargs["raw"] is False and not instance.has_focal_point():
|
|
28
|
+
# Set the focal point
|
|
29
|
+
set_image_focal_point_task.enqueue(
|
|
30
|
+
instance._meta.app_label, instance._meta.model_name, instance.pk
|
|
31
|
+
)
|
|
25
32
|
|
|
26
33
|
|
|
27
34
|
def register_signal_handlers():
|
|
28
35
|
Image = get_image_model()
|
|
29
36
|
Rendition = Image.get_rendition_model()
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
post_save.connect(post_save_image_feature_detection, sender=Image)
|
|
32
39
|
post_delete.connect(post_delete_file_cleanup, sender=Image)
|
|
33
40
|
post_delete.connect(post_delete_file_cleanup, sender=Rendition)
|
|
34
41
|
post_delete.connect(post_delete_purge_rendition_cache, sender=Rendition)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
$((function(){$(
|
|
1
|
+
$((function(){$("#fileupload").fileupload({dataType:"html",sequentialUploads:!0,dropZone:$(".drop-zone"),previewMinWidth:150,previewMaxWidth:150,previewMinHeight:150,previewMaxHeight:150,add:function(e,t){var a=$(this),o=a.data("blueimp-fileupload")||a.data("fileupload"),s=$($("#upload-list-item").html()).addClass("upload-uploading"),i=o.options;$("#upload-list").append(s),t.context=s,t.process((function(){return a.fileupload("process",t)})).always((function(){t.context.removeClass("processing"),t.context.find(".left").each((function(e,a){$(a).append(escapeHtml(t.files[e].name))})),t.context.find(".preview .thumb").each((function(e,a){$(a).find(".icon").remove(),$(a).append(t.files[e].preview)}))})).done((function(){t.context.find(".start").prop("disabled",!1),!1!==o._trigger("added",e,t)&&(i.autoUpload||t.autoUpload)&&!1!==t.autoUpload&&t.submit()})).fail((function(){t.files.error&&t.context.each((function(e){var a=t.files[e].error;a&&$(this).find(".error_messages").html(a)}))}))},processfail:function(e,t){$(t.context).removeClass("upload-uploading").addClass("upload-failure")},progress:function(e,t){if(e.isDefaultPrevented())return!1;var a=Math.floor(t.loaded/t.total*100);t.context.each((function(){$(this).find(".progress").addClass("active").attr("aria-valuenow",a).find(".bar").css("width",a+"%").html(a+"%")}))},progressall:function(e,t){var a=parseInt(t.loaded/t.total*100,10);$("#overall-progress").addClass("active").attr("aria-valuenow",a).find(".bar").css("width",a+"%").html(a+"%"),a>=100&&$("#overall-progress").removeClass("active").find(".bar").css("width","0%")},formData:function(e){var t=this.files[0].name,a={title:t.replace(/\.[^.]+$/,"")};return e.get(0).dispatchEvent(new CustomEvent("wagtail:images-upload",{bubbles:!0,cancelable:!0,detail:{data:a,filename:t,maxTitleLength:this.maxTitleLength}}))?e.serializeArray().concat({name:"title",value:a.title}):e.serializeArray()},done:function(e,t){var a=$(t.context),o=JSON.parse(t.result);o.success?o.duplicate?(a.addClass("upload-duplicate"),$(".right",a).append(o.confirm_duplicate_upload),$(".confirm-duplicate-upload",a).on("click",".confirm-upload",(function(e){e.preventDefault(),$(this).closest(".confirm-duplicate-upload").remove(),$(".right",a).append(o.form)}))):(a.addClass("upload-success"),$(".right",a).append(o.form)):(a.addClass("upload-failure"),$(".right .error_messages",a).append(o.error_message))},fail:function(e,t){var a=$(t.context),o=$(".server-error",a);$(".error-text",o).text(t.errorThrown),$(".error-code",o).text(t.jqXHR.status),a.addClass("upload-server-error")},always:function(e,t){$(t.context).removeClass("upload-uploading").addClass("upload-complete")}}),$("#upload-list").on("submit","form",(function(e){var t=$(this),a=new FormData(this),o=t.closest("#upload-list > li");e.preventDefault(),$.ajax({contentType:!1,data:a,processData:!1,type:"POST",url:this.action}).done((function(e){if(e.success){var a=$(".status-msg.update-success").first().text();document.dispatchEvent(new CustomEvent("w-messages:add",{detail:{clear:!0,text:a,type:"success"}})),o.slideUp((function(){$(this).remove()}))}else t.replaceWith(e.form)}))})),$("#upload-list").on("click",".delete",(function(e){var t=$(this).closest("form"),a=t.closest("#upload-list > li");e.preventDefault();var o=$('input[name="csrfmiddlewaretoken"]',t).val();$.post(this.href,{csrfmiddlewaretoken:o},(function(e){e.success&&a.slideUp((function(){$(this).remove()}))}))}))}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{class e extends window.wagtailStreamField.blocks.StructBlockDefinition{render(e,t,
|
|
1
|
+
(()=>{class e extends window.wagtailStreamField.blocks.StructBlockDefinition{render(e,t,a,l){const d=super.render(e,t,a,l),i=document.getElementById(`${t}-alt_text`),n=document.getElementById(`${t}-decorative`),c=()=>{n.checked?i.setAttribute("disabled",!0):i.removeAttribute("disabled")};c(),n.addEventListener("change",c);const o=d.childBlocks.image.widget;let r=a?.image?.default_alt_text||"";return o.on("chosen",(e=>{i.value===r&&(i.value=e.default_alt_text),r=e.default_alt_text})),d}}window.telepath.register("wagtail.images.blocks.ImageBlock",e)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,t={7199:(e,t,r)=>{var i=r(9465);class
|
|
1
|
+
(()=>{"use strict";var e,t={7199:(e,t,r)=>{var i=r(9465);class a extends i.y{chooserModalClass=ImageChooserModal;initHTMLElements(e){super.initHTMLElements(e),this.previewImage=this.chooserElement.querySelector("[data-chooser-image]")}getStateFromHTML(){const e=super.getStateFromHTML();return e&&(e.preview={url:this.previewImage.getAttribute("src"),width:this.previewImage.getAttribute("width"),height:this.previewImage.getAttribute("height")},e.default_alt_text=this.previewImage.getAttribute("data-default-alt-text")),e}renderState(e){super.renderState(e),this.previewImage.setAttribute("src",e.preview.url),this.previewImage.setAttribute("width",e.preview.width),this.previewImage.setAttribute("data-default-alt-text",e.default_alt_text)}}class o extends i._{widgetClass=a;chooserModalClass=ImageChooserModal}window.telepath.register("wagtail.images.widgets.ImageChooser",o)},1669:e=>{e.exports=jQuery}},r={};function i(e){var a=r[e];if(void 0!==a)return a.exports;var o=r[e]={exports:{}};return t[e](o,o.exports,i),o.exports}i.m=t,e=[],i.O=(t,r,a,o)=>{if(!r){var s=1/0;for(h=0;h<e.length;h++){for(var[r,a,o]=e[h],l=!0,n=0;n<r.length;n++)(!1&o||s>=o)&&Object.keys(i.O).every((e=>i.O[e](r[n])))?r.splice(n--,1):(l=!1,o<s&&(s=o));if(l){e.splice(h--,1);var u=a();void 0!==u&&(t=u)}}return t}o=o||0;for(var h=e.length;h>0&&e[h-1][2]>o;h--)e[h]=e[h-1];e[h]=[r,a,o]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.j=246,(()=>{var e={246:0};i.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,[s,l,n]=r,u=0;if(s.some((t=>0!==e[t]))){for(a in l)i.o(l,a)&&(i.m[a]=l[a]);if(n)var h=n(i)}for(t&&t(r);u<s.length;u++)o=s[u],i.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return i.O(h)},r=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var a=i.O(void 0,[321],(()=>i(7199)));a=i.O(a)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,t={4023:(e,t,r)=>{var i=r(9465);class
|
|
1
|
+
(()=>{"use strict";var e,t={4023:(e,t,r)=>{var i=r(9465);class a extends i.y{chooserModalClass=ImageChooserModal;initHTMLElements(e){super.initHTMLElements(e),this.previewImage=this.chooserElement.querySelector("[data-chooser-image]")}getStateFromHTML(){const e=super.getStateFromHTML();return e&&(e.preview={url:this.previewImage.getAttribute("src"),width:this.previewImage.getAttribute("width"),height:this.previewImage.getAttribute("height")},e.default_alt_text=this.previewImage.getAttribute("data-default-alt-text")),e}renderState(e){super.renderState(e),this.previewImage.setAttribute("src",e.preview.url),this.previewImage.setAttribute("width",e.preview.width),this.previewImage.setAttribute("data-default-alt-text",e.default_alt_text)}}window.ImageChooser=a},1669:e=>{e.exports=jQuery}},r={};function i(e){var a=r[e];if(void 0!==a)return a.exports;var o=r[e]={exports:{}};return t[e](o,o.exports,i),o.exports}i.m=t,e=[],i.O=(t,r,a,o)=>{if(!r){var n=1/0;for(h=0;h<e.length;h++){for(var[r,a,o]=e[h],s=!0,l=0;l<r.length;l++)(!1&o||n>=o)&&Object.keys(i.O).every((e=>i.O[e](r[l])))?r.splice(l--,1):(s=!1,o<n&&(n=o));if(s){e.splice(h--,1);var u=a();void 0!==u&&(t=u)}}return t}o=o||0;for(var h=e.length;h>0&&e[h-1][2]>o;h--)e[h]=e[h-1];e[h]=[r,a,o]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.j=306,(()=>{var e={306:0};i.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,[n,s,l]=r,u=0;if(n.some((t=>0!==e[t]))){for(a in s)i.o(s,a)&&(i.m[a]=s[a]);if(l)var h=l(i)}for(t&&t(r);u<n.length;u++)o=n[u],i.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return i.O(h)},r=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var a=i.O(void 0,[321],(()=>i(4023)));a=i.O(a)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
$((function(){$("[data-generator-url]").each((function(){var i=$(this),
|
|
1
|
+
$((function(){$("[data-generator-url]").each((function(){var i=$(this),e=i.find("form"),n=e.find("select#id_filter_method"),a=e.find("input#id_width"),l=e.find("input#id_height"),r=e.find("input#id_closeness"),t=i.find("#result-url"),d=i.find(".loading-mask"),o=i.find("img.preview"),f=i.data("generatorUrl");function s(){var i=n.val();d.addClass("loading"),"width"===i?i+="-"+a.val():"height"===i?i+="-"+l.val():"min"!==i&&"max"!==i&&"fill"!==i||(i+="fill"===i?"-"+a.val()+"x"+l.val()+"-c"+r.val():"-"+a.val()+"x"+l.val()),$.getJSON(f.replace("__filterspec__",i)).done((function(i){t.val(i.url),o.attr("src",i.preview_url),d.removeClass("loading")})).fail((function(i){t.val(i.responseJSON.error),o.attr("src",""),d.removeClass("loading")}))}e.on("change",$.debounce(500,s)),e.on("keyup",$.debounce(500,s)),s()}))}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery","load-image","load-image-meta","load-image-exif","load-image-ios","
|
|
1
|
+
!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery","load-image","load-image-meta","load-image-exif","load-image-ios","./jquery.fileupload-process"],e):e(window.jQuery,window.loadImage)}((function(e,i){"use strict";e.blueimp.fileupload.prototype.options.processQueue.unshift({action:"loadImageMetaData",disableImageHead:"@",disableExif:"@",disableExifThumbnail:"@",disableExifSub:"@",disableExifGps:"@",disabled:"@disableImageMetaDataLoad"},{action:"loadImage",prefix:!0,fileTypes:"@",maxFileSize:"@",noRevoke:"@",disabled:"@disableImageLoad"},{action:"resizeImage",prefix:"image",maxWidth:"@",maxHeight:"@",minWidth:"@",minHeight:"@",crop:"@",orientation:"@",forceResize:"@",disabled:"@disableImageResize"},{action:"saveImage",quality:"@imageQuality",type:"@imageType",disabled:"@disableImageResize"},{action:"saveImageMetaData",disabled:"@disableImageMetaDataSave"},{action:"resizeImage",prefix:"preview",maxWidth:"@",maxHeight:"@",minWidth:"@",minHeight:"@",crop:"@",orientation:"@",thumbnail:"@",canvas:"@",disabled:"@disableImagePreview"},{action:"setImage",name:"@imagePreviewName",disabled:"@disableImagePreview"},{action:"deleteImageReferences",disabled:"@disableImageReferencesDeletion"}),e.widget("blueimp.fileupload",e.blueimp.fileupload,{options:{loadImageFileTypes:/^image\/(gif|jpeg|png|svg\+xml)$/,loadImageMaxFileSize:1e7,imageMaxWidth:1920,imageMaxHeight:1080,imageOrientation:!1,imageCrop:!1,disableImageResize:!0,previewMaxWidth:80,previewMaxHeight:80,previewOrientation:!0,previewThumbnail:!0,previewCrop:!1,previewCanvas:!0},processActions:{loadImage:function(a,t){if(t.disabled)return a;var n=this,s=a.files[a.index],r=e.Deferred();return"number"===e.type(t.maxFileSize)&&s.size>t.maxFileSize||t.fileTypes&&!t.fileTypes.test(s.type)||!i(s,(function(e){e.src&&(a.img=e),r.resolveWith(n,[a])}),t)?a:r.promise()},resizeImage:function(a,t){if(t.disabled||!a.canvas&&!a.img)return a;t=e.extend({canvas:!0},t);var n,s=this,r=e.Deferred(),d=t.canvas&&a.canvas||a.img,o=function(e){e&&(e.width!==d.width||e.height!==d.height||t.forceResize)&&(a[e.getContext?"canvas":"img"]=e),a.preview=e,r.resolveWith(s,[a])};if(a.exif){if(!0===t.orientation&&(t.orientation=a.exif.get("Orientation")),t.thumbnail&&(n=a.exif.get("Thumbnail")))return i(n,o,t),r.promise();a.orientation?delete t.orientation:a.orientation=t.orientation}return d?(o(i.scale(d,t)),r.promise()):a},saveImage:function(i,a){if(!i.canvas||a.disabled)return i;var t=this,n=i.files[i.index],s=e.Deferred();return i.canvas.toBlob?(i.canvas.toBlob((function(e){e.name||(n.type===e.type?e.name=n.name:n.name&&(e.name=n.name.replace(/\..+$/,"."+e.type.substr(6)))),n.type!==e.type&&delete i.imageHead,i.files[i.index]=e,s.resolveWith(t,[i])}),a.type||n.type,a.quality),s.promise()):i},loadImageMetaData:function(a,t){if(t.disabled)return a;var n=this,s=e.Deferred();return i.parseMetaData(a.files[a.index],(function(i){e.extend(a,i),s.resolveWith(n,[a])}),t),s.promise()},saveImageMetaData:function(e,i){if(!(e.imageHead&&e.canvas&&e.canvas.toBlob)||i.disabled)return e;var a=e.files[e.index],t=new Blob([e.imageHead,this._blobSlice.call(a,20)],{type:a.type});return t.name=a.name,e.files[e.index]=t,e},setImage:function(e,i){return e.preview&&!i.disabled&&(e.files[e.index][i.name||"preview"]=e.preview),e},deleteImageReferences:function(e,i){return i.disabled||(delete e.img,delete e.canvas,delete e.preview,delete e.imageHead),e}}})}));
|
wagtail/images/tasks.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from django.apps import apps
|
|
2
|
+
from django_tasks import task
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@task()
|
|
6
|
+
def set_image_focal_point_task(app_label, model_name, pk):
|
|
7
|
+
model = apps.get_model(app_label, model_name)
|
|
8
|
+
instance = model.objects.get(pk=pk)
|
|
9
|
+
instance.set_focal_point(instance.get_suggested_focal_point())
|
|
10
|
+
|
|
11
|
+
instance.save(
|
|
12
|
+
update_fields=[
|
|
13
|
+
"focal_point_x",
|
|
14
|
+
"focal_point_y",
|
|
15
|
+
"focal_point_width",
|
|
16
|
+
"focal_point_height",
|
|
17
|
+
]
|
|
18
|
+
)
|
|
@@ -63,9 +63,7 @@
|
|
|
63
63
|
|
|
64
64
|
<dt>{% trans "Usage" %}</dt>
|
|
65
65
|
<dd>
|
|
66
|
-
{% with
|
|
67
|
-
<a href="{{ image.usage_url }}">{% blocktrans trimmed with usage_count=usage_count_val|intcomma count usage_count_val=usage_count_val %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
|
68
|
-
{% endwith %}
|
|
66
|
+
<a href="{{ image.usage_url }}">{% blocktrans trimmed with usage_count=usage_count_val|intcomma count usage_count_val=usage_count_val %}Used {{ usage_count }} time{% plural %}Used {{ usage_count }} times{% endblocktrans %}</a>
|
|
69
67
|
</dd>
|
|
70
68
|
</dl>
|
|
71
69
|
</div>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
{% block main_content %}
|
|
13
13
|
<div class="w-image-url-generator w-mt-8" data-generator-url="{% url 'wagtailimages:generate_url' object.id '__filterspec__' %}">
|
|
14
|
-
<form class="w-image-url-generator__form w-mb-5">
|
|
14
|
+
<form class="w-image-url-generator__form w-mb-5" data-controller="w-rules" data-action="change->w-rules#resolve keyup->w-rules#resolve">
|
|
15
15
|
{% include "wagtailadmin/shared/field.html" with field=form.filter_method %}
|
|
16
16
|
{% field_row max_content=True %}
|
|
17
17
|
{% include "wagtailadmin/shared/field.html" with field=form.width %}
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
{% endblock %}
|
|
11
11
|
|
|
12
12
|
{% block main_content %}
|
|
13
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
class="drop-zone w-mt-8"
|
|
15
|
+
data-controller="w-zone"
|
|
16
|
+
data-action="dragover@document->w-zone#noop:prevent drop@document->w-zone#noop:prevent dragover->w-zone#activate drop->w-zone#deactivate dragleave->w-zone#deactivate dragend->w-zone#deactivate"
|
|
17
|
+
data-w-zone-active-class="hovered"
|
|
18
|
+
data-w-zone-delay-value="10"
|
|
19
|
+
>
|
|
14
20
|
<p>{% trans "Drag and drop images into this area to upload immediately." %}</p>
|
|
15
21
|
<p>{{ help_text }}</p>
|
|
16
22
|
|
|
@@ -89,7 +95,6 @@
|
|
|
89
95
|
|
|
90
96
|
<!-- this exact order of plugins is vital -->
|
|
91
97
|
<script src="{% versioned_static 'wagtailimages/js/vendor/load-image.min.js' %}"></script>
|
|
92
|
-
<script src="{% versioned_static 'wagtailimages/js/vendor/canvas-to-blob.min.js' %}"></script>
|
|
93
98
|
<script src="{% versioned_static 'wagtailadmin/js/vendor/jquery.iframe-transport.js' %}"></script>
|
|
94
99
|
<script src="{% versioned_static 'wagtailadmin/js/vendor/jquery.fileupload.js' %}"></script>
|
|
95
100
|
<script src="{% versioned_static 'wagtailadmin/js/vendor/jquery.fileupload-process.js' %}"></script>
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
|
|
4
4
|
{% block chosen_icon %}
|
|
5
5
|
{# Empty alt because the chosen item’s title is already displayed next to the image. #}
|
|
6
|
-
<img class="chooser__image show-transparency" data-chooser-image alt="" decoding="async" height="{{ preview.height|unlocalize }}" src="{{ preview.url }}" width="{{ preview.width|unlocalize }}">
|
|
6
|
+
<img class="chooser__image show-transparency" data-chooser-image alt="" data-default-alt-text="{{ default_alt_text }}" decoding="async" height="{{ preview.height|unlocalize }}" src="{{ preview.url }}" width="{{ preview.width|unlocalize }}">
|
|
7
7
|
{% endblock chosen_icon %}
|
|
@@ -1453,7 +1453,8 @@ class TestImageDeleteView(WagtailTestUtils, TestCase):
|
|
|
1453
1453
|
self.assertEqual(response.status_code, 302)
|
|
1454
1454
|
|
|
1455
1455
|
def test_delete_get_with_protected_reference(self):
|
|
1456
|
-
|
|
1456
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1457
|
+
VariousOnDeleteModel.objects.create(protected_image=self.image)
|
|
1457
1458
|
response = self.get()
|
|
1458
1459
|
self.assertEqual(response.status_code, 200)
|
|
1459
1460
|
self.assertTemplateUsed(response, "wagtailimages/images/confirm_delete.html")
|
|
@@ -1476,7 +1477,8 @@ class TestImageDeleteView(WagtailTestUtils, TestCase):
|
|
|
1476
1477
|
)
|
|
1477
1478
|
|
|
1478
1479
|
def test_delete_post_with_protected_reference(self):
|
|
1479
|
-
|
|
1480
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1481
|
+
VariousOnDeleteModel.objects.create(protected_image=self.image)
|
|
1480
1482
|
response = self.post()
|
|
1481
1483
|
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
1482
1484
|
self.assertTrue(Image.objects.filter(id=self.image.id).exists())
|
|
@@ -1493,18 +1495,19 @@ class TestUsage(WagtailTestUtils, TestCase):
|
|
|
1493
1495
|
)
|
|
1494
1496
|
|
|
1495
1497
|
def test_usage_page(self):
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1498
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1499
|
+
home_page = Page.objects.get(id=2)
|
|
1500
|
+
home_page.add_child(
|
|
1501
|
+
instance=EventPage(
|
|
1502
|
+
title="Christmas",
|
|
1503
|
+
slug="christmas",
|
|
1504
|
+
feed_image=self.image,
|
|
1505
|
+
date_from=datetime.date.today(),
|
|
1506
|
+
audience="private",
|
|
1507
|
+
location="Test",
|
|
1508
|
+
cost="Test",
|
|
1509
|
+
)
|
|
1510
|
+
).save_revision().publish()
|
|
1508
1511
|
|
|
1509
1512
|
response = self.client.get(
|
|
1510
1513
|
reverse("wagtailimages:image_usage", args=[self.image.id])
|
|
@@ -1521,9 +1524,10 @@ class TestUsage(WagtailTestUtils, TestCase):
|
|
|
1521
1524
|
self.assertNotContains(response, '<table class="listing">')
|
|
1522
1525
|
|
|
1523
1526
|
def test_usage_no_tags(self):
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1528
|
+
# tags should not count towards an image's references
|
|
1529
|
+
self.image.tags.add("illustration")
|
|
1530
|
+
self.image.save()
|
|
1527
1531
|
response = self.client.get(
|
|
1528
1532
|
reverse("wagtailimages:image_usage", args=[self.image.id])
|
|
1529
1533
|
)
|
|
@@ -1531,18 +1535,19 @@ class TestUsage(WagtailTestUtils, TestCase):
|
|
|
1531
1535
|
self.assertNotContains(response, '<table class="listing">')
|
|
1532
1536
|
|
|
1533
1537
|
def test_usage_page_with_only_change_permission(self):
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1538
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1539
|
+
home_page = Page.objects.get(id=2)
|
|
1540
|
+
home_page.add_child(
|
|
1541
|
+
instance=EventPage(
|
|
1542
|
+
title="Christmas",
|
|
1543
|
+
slug="christmas",
|
|
1544
|
+
feed_image=self.image,
|
|
1545
|
+
date_from=datetime.date.today(),
|
|
1546
|
+
audience="private",
|
|
1547
|
+
location="Test",
|
|
1548
|
+
cost="Test",
|
|
1549
|
+
)
|
|
1550
|
+
).save_revision().publish()
|
|
1546
1551
|
|
|
1547
1552
|
# Create a user with change_image permission but not add_image
|
|
1548
1553
|
user = self.create_user(
|
|
@@ -1871,6 +1876,7 @@ class TestImageChooserChosenView(WagtailTestUtils, TestCase):
|
|
|
1871
1876
|
self.image = Image.objects.create(
|
|
1872
1877
|
title="Test image",
|
|
1873
1878
|
file=get_test_image_file(),
|
|
1879
|
+
description="Test description",
|
|
1874
1880
|
)
|
|
1875
1881
|
|
|
1876
1882
|
def get(self, params={}):
|
|
@@ -1885,6 +1891,12 @@ class TestImageChooserChosenView(WagtailTestUtils, TestCase):
|
|
|
1885
1891
|
response_json = json.loads(response.content.decode())
|
|
1886
1892
|
self.assertEqual(response_json["step"], "chosen")
|
|
1887
1893
|
self.assertEqual(response_json["result"]["title"], "Test image")
|
|
1894
|
+
self.assertEqual(
|
|
1895
|
+
set(response_json["result"]["preview"].keys()), {"url", "width", "height"}
|
|
1896
|
+
)
|
|
1897
|
+
self.assertEqual(
|
|
1898
|
+
response_json["result"]["default_alt_text"], "Test description"
|
|
1899
|
+
)
|
|
1888
1900
|
|
|
1889
1901
|
def test_with_multiple_flag(self):
|
|
1890
1902
|
# if 'multiple' is passed as a URL param, the result should be returned as a single-item list
|
|
@@ -1895,6 +1907,13 @@ class TestImageChooserChosenView(WagtailTestUtils, TestCase):
|
|
|
1895
1907
|
self.assertEqual(response_json["step"], "chosen")
|
|
1896
1908
|
self.assertEqual(len(response_json["result"]), 1)
|
|
1897
1909
|
self.assertEqual(response_json["result"][0]["title"], "Test image")
|
|
1910
|
+
self.assertEqual(
|
|
1911
|
+
set(response_json["result"][0]["preview"].keys()),
|
|
1912
|
+
{"url", "width", "height"},
|
|
1913
|
+
)
|
|
1914
|
+
self.assertEqual(
|
|
1915
|
+
response_json["result"][0]["default_alt_text"], "Test description"
|
|
1916
|
+
)
|
|
1898
1917
|
|
|
1899
1918
|
|
|
1900
1919
|
class TestImageChooserChosenMultipleView(WagtailTestUtils, TestCase):
|
|
@@ -1905,15 +1924,18 @@ class TestImageChooserChosenMultipleView(WagtailTestUtils, TestCase):
|
|
|
1905
1924
|
self.image1 = Image.objects.create(
|
|
1906
1925
|
title="Test image",
|
|
1907
1926
|
file=get_test_image_file(),
|
|
1927
|
+
description="Test description",
|
|
1908
1928
|
)
|
|
1909
1929
|
self.image2 = Image.objects.create(
|
|
1910
1930
|
title="Another test image",
|
|
1911
1931
|
file=get_test_image_file(),
|
|
1932
|
+
description="Another test description",
|
|
1912
1933
|
)
|
|
1913
1934
|
|
|
1914
1935
|
self.image3 = Image.objects.create(
|
|
1915
1936
|
title="Unchosen test image",
|
|
1916
1937
|
file=get_test_image_file(),
|
|
1938
|
+
description="Unchosen test description",
|
|
1917
1939
|
)
|
|
1918
1940
|
|
|
1919
1941
|
def get(self, params={}):
|
|
@@ -1935,6 +1957,8 @@ class TestImageChooserChosenMultipleView(WagtailTestUtils, TestCase):
|
|
|
1935
1957
|
self.assertEqual(len(response_json["result"]), 2)
|
|
1936
1958
|
titles = {item["title"] for item in response_json["result"]}
|
|
1937
1959
|
self.assertEqual(titles, {"Test image", "Another test image"})
|
|
1960
|
+
alt_texts = {item["default_alt_text"] for item in response_json["result"]}
|
|
1961
|
+
self.assertEqual(alt_texts, {"Test description", "Another test description"})
|
|
1938
1962
|
|
|
1939
1963
|
|
|
1940
1964
|
class TestImageChooserSelectFormatView(WagtailTestUtils, TestCase):
|
|
@@ -236,7 +236,7 @@ class TestImageBlock(TestImageChooserBlock):
|
|
|
236
236
|
value = block.to_python(self.image.id)
|
|
237
237
|
|
|
238
238
|
self.assertEqual(value.id, self.image.id)
|
|
239
|
-
self.assertEqual(value.contextual_alt_text,
|
|
239
|
+
self.assertEqual(value.contextual_alt_text, "Test image") # Defaulted to title
|
|
240
240
|
self.assertFalse(value.decorative)
|
|
241
241
|
|
|
242
242
|
def test_to_python_with_dict(self):
|
|
@@ -267,8 +267,9 @@ class TestImageBlock(TestImageChooserBlock):
|
|
|
267
267
|
|
|
268
268
|
def test_bulk_to_python_with_list_of_ints(self):
|
|
269
269
|
block = ImageBlock(required=False)
|
|
270
|
+
single_image = block.to_python(self.image.id)
|
|
270
271
|
result = block.bulk_to_python([None, self.image.id, self.image.id])
|
|
271
|
-
self.assertEqual(result, [None,
|
|
272
|
+
self.assertEqual(result, [None, single_image, single_image])
|
|
272
273
|
|
|
273
274
|
def test_bulk_to_python_with_list_of_dicts(self):
|
|
274
275
|
block = ImageBlock(required=False)
|
|
@@ -984,11 +984,12 @@ class TestUsageCount(TestCase):
|
|
|
984
984
|
self.assertEqual(self.image.get_usage().count(), 0)
|
|
985
985
|
|
|
986
986
|
def test_used_image_document_usage_count(self):
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
987
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
988
|
+
page = EventPage.objects.get(id=4)
|
|
989
|
+
event_page_carousel_item = EventPageCarouselItem()
|
|
990
|
+
event_page_carousel_item.page = page
|
|
991
|
+
event_page_carousel_item.image = self.image
|
|
992
|
+
event_page_carousel_item.save()
|
|
992
993
|
self.assertEqual(self.image.get_usage().count(), 1)
|
|
993
994
|
|
|
994
995
|
|
|
@@ -1005,11 +1006,12 @@ class TestGetUsage(TestCase):
|
|
|
1005
1006
|
self.assertEqual(list(self.image.get_usage()), [])
|
|
1006
1007
|
|
|
1007
1008
|
def test_used_image_document_get_usage(self):
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1009
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
1010
|
+
page = EventPage.objects.get(id=4)
|
|
1011
|
+
event_page_carousel_item = EventPageCarouselItem()
|
|
1012
|
+
event_page_carousel_item.page = page
|
|
1013
|
+
event_page_carousel_item.image = self.image
|
|
1014
|
+
event_page_carousel_item.save()
|
|
1013
1015
|
|
|
1014
1016
|
self.assertIsInstance(self.image.get_usage()[0], tuple)
|
|
1015
1017
|
self.assertIsInstance(self.image.get_usage()[0][0], Page)
|
wagtail/images/tests/tests.py
CHANGED
|
@@ -366,6 +366,8 @@ class TestFrontendServeView(TestCase):
|
|
|
366
366
|
self.assertEqual(response.status_code, 200)
|
|
367
367
|
self.assertTrue(response.streaming)
|
|
368
368
|
self.assertEqual(response["Content-Type"], "image/png")
|
|
369
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
370
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
369
371
|
# Ensure the file can actually be read
|
|
370
372
|
image = willow.Image.open(b"".join(response.streaming_content))
|
|
371
373
|
self.assertIsInstance(image, PNGImageFile)
|
|
@@ -385,6 +387,8 @@ class TestFrontendServeView(TestCase):
|
|
|
385
387
|
self.assertEqual(response.status_code, 200)
|
|
386
388
|
self.assertTrue(response.streaming)
|
|
387
389
|
self.assertEqual(response["Content-Type"], "image/svg+xml")
|
|
390
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
391
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
388
392
|
# Ensure the file can actually be read
|
|
389
393
|
image = willow.Image.open(BytesIO(b"".join(response.streaming_content)))
|
|
390
394
|
self.assertIsInstance(image, SvgImageFile)
|
|
@@ -462,6 +466,8 @@ class TestFrontendServeView(TestCase):
|
|
|
462
466
|
self.assertEqual(response.status_code, 200)
|
|
463
467
|
self.assertTrue(response.streaming)
|
|
464
468
|
self.assertEqual(response["Content-Type"], "image/png")
|
|
469
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
470
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
465
471
|
# Ensure the file can actually be read
|
|
466
472
|
image = willow.Image.open(b"".join(response.streaming_content))
|
|
467
473
|
self.assertIsInstance(image, PNGImageFile)
|
|
@@ -627,6 +633,8 @@ class TestFrontendSendfileView(TestCase):
|
|
|
627
633
|
|
|
628
634
|
self.assertEqual(response.status_code, 200)
|
|
629
635
|
self.assertEqual(response["Content-Type"], "image/png")
|
|
636
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
637
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
630
638
|
|
|
631
639
|
@override_settings(SENDFILE_BACKEND="sendfile.backends.development")
|
|
632
640
|
def test_sendfile_dummy_backend(self):
|
|
@@ -640,6 +648,8 @@ class TestFrontendSendfileView(TestCase):
|
|
|
640
648
|
|
|
641
649
|
self.assertEqual(response.status_code, 200)
|
|
642
650
|
self.assertTrue(response.content, msg="Dummy backend response")
|
|
651
|
+
self.assertEqual(response["Content-Security-Policy"], "default-src 'none'")
|
|
652
|
+
self.assertEqual(response["X-Content-Type-Options"], "nosniff")
|
|
643
653
|
|
|
644
654
|
|
|
645
655
|
class TestRect(TestCase):
|
wagtail/images/views/chooser.py
CHANGED
wagtail/images/views/images.py
CHANGED
|
@@ -134,7 +134,6 @@ class EditView(generic.EditView):
|
|
|
134
134
|
url_generator_url_name = "wagtailimages:url_generator"
|
|
135
135
|
header_icon = "image"
|
|
136
136
|
context_object_name = "image"
|
|
137
|
-
_show_breadcrumbs = True
|
|
138
137
|
|
|
139
138
|
@cached_property
|
|
140
139
|
def model(self):
|
|
@@ -186,6 +185,7 @@ class EditView(generic.EditView):
|
|
|
186
185
|
def get_context_data(self, **kwargs):
|
|
187
186
|
context = super().get_context_data(**kwargs)
|
|
188
187
|
context["next"] = self.next_url
|
|
188
|
+
context["usage_count_val"] = self.object.get_usage().count()
|
|
189
189
|
|
|
190
190
|
try:
|
|
191
191
|
context["filesize"] = self.object.get_file_size()
|
|
@@ -212,7 +212,6 @@ class URLGeneratorView(generic.InspectView):
|
|
|
212
212
|
template_name = "wagtailimages/images/url_generator.html"
|
|
213
213
|
index_url_name = "wagtailimages:index"
|
|
214
214
|
edit_url_name = "wagtailimages:edit"
|
|
215
|
-
_show_breadcrumbs = True
|
|
216
215
|
|
|
217
216
|
def get_page_subtitle(self):
|
|
218
217
|
return self.object.title
|
|
@@ -346,7 +345,6 @@ class CreateView(generic.CreateView):
|
|
|
346
345
|
error_message = gettext_lazy("The image could not be created due to errors.")
|
|
347
346
|
template_name = "wagtailimages/images/add.html"
|
|
348
347
|
header_icon = "image"
|
|
349
|
-
_show_breadcrumbs = True
|
|
350
348
|
|
|
351
349
|
@cached_property
|
|
352
350
|
def model(self):
|
wagtail/images/views/multiple.py
CHANGED
|
@@ -27,7 +27,6 @@ class AddView(WagtailAdminTemplateMixin, BaseAddView):
|
|
|
27
27
|
template_name = "wagtailimages/multiple/add.html"
|
|
28
28
|
header_icon = "image"
|
|
29
29
|
page_title = gettext_lazy("Add images")
|
|
30
|
-
_show_breadcrumbs = True
|
|
31
30
|
|
|
32
31
|
index_url_name = "wagtailimages:index"
|
|
33
32
|
edit_object_url_name = "wagtailimages:edit_multiple"
|
wagtail/images/views/serve.py
CHANGED
|
@@ -66,7 +66,15 @@ class ServeView(View):
|
|
|
66
66
|
|
|
67
67
|
# Serve the file
|
|
68
68
|
rendition.file.open("rb")
|
|
69
|
-
|
|
69
|
+
response = FileResponse(rendition.file, content_type=mime_type)
|
|
70
|
+
|
|
71
|
+
# Add a CSP header to prevent inline execution
|
|
72
|
+
response["Content-Security-Policy"] = "default-src 'none'"
|
|
73
|
+
|
|
74
|
+
# Prevent browsers from auto-detecting the content-type of a document
|
|
75
|
+
response["X-Content-Type-Options"] = "nosniff"
|
|
76
|
+
|
|
77
|
+
return response
|
|
70
78
|
|
|
71
79
|
def redirect(self, rendition):
|
|
72
80
|
# Redirect to the file's public location
|
|
@@ -80,4 +88,12 @@ class SendFileView(ServeView):
|
|
|
80
88
|
backend = None
|
|
81
89
|
|
|
82
90
|
def serve(self, rendition):
|
|
83
|
-
|
|
91
|
+
response = sendfile(self.request, rendition.file.path, backend=self.backend)
|
|
92
|
+
|
|
93
|
+
# Add a CSP header to prevent inline execution
|
|
94
|
+
response["Content-Security-Policy"] = "default-src 'none'"
|
|
95
|
+
|
|
96
|
+
# Prevent browsers from auto-detecting the content-type of a document
|
|
97
|
+
response["X-Content-Type-Options"] = "nosniff"
|
|
98
|
+
|
|
99
|
+
return response
|
wagtail/images/widgets.py
CHANGED
|
@@ -31,11 +31,13 @@ class AdminImageChooser(BaseChooser):
|
|
|
31
31
|
"width": preview_image.width,
|
|
32
32
|
"height": preview_image.height,
|
|
33
33
|
}
|
|
34
|
+
data["default_alt_text"] = instance.default_alt_text
|
|
34
35
|
return data
|
|
35
36
|
|
|
36
37
|
def get_context(self, name, value_data, attrs):
|
|
37
38
|
context = super().get_context(name, value_data, attrs)
|
|
38
39
|
context["preview"] = value_data.get("preview", {})
|
|
40
|
+
context["default_alt_text"] = value_data.get("default_alt_text", "")
|
|
39
41
|
return context
|
|
40
42
|
|
|
41
43
|
@property
|
|
@@ -44,6 +46,7 @@ class AdminImageChooser(BaseChooser):
|
|
|
44
46
|
js=[
|
|
45
47
|
versioned_static("wagtailimages/js/image-chooser-modal.js"),
|
|
46
48
|
versioned_static("wagtailimages/js/image-chooser.js"),
|
|
49
|
+
versioned_static("wagtailimages/js/image-chooser-telepath.js"),
|
|
47
50
|
]
|
|
48
51
|
)
|
|
49
52
|
|