wagtail 7.2.1__py3-none-any.whl → 7.3rc1__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/copy_for_translation.py +4 -2
- wagtail/admin/action_menu.py +4 -1
- wagtail/admin/api/actions/convert_alias.py +2 -2
- wagtail/admin/api/actions/copy.py +2 -2
- wagtail/admin/api/actions/copy_for_translation.py +2 -2
- wagtail/admin/api/actions/create_alias.py +2 -2
- wagtail/admin/api/actions/delete.py +1 -1
- wagtail/admin/api/actions/move.py +1 -1
- wagtail/admin/api/actions/publish.py +2 -2
- wagtail/admin/api/actions/revert_to_page_revision.py +2 -2
- wagtail/admin/api/actions/unpublish.py +1 -1
- wagtail/admin/api/filters.py +2 -2
- wagtail/admin/compare.py +22 -0
- wagtail/admin/forms/account.py +52 -1
- wagtail/admin/forms/comments.py +53 -0
- wagtail/admin/forms/models.py +36 -0
- wagtail/admin/forms/pages.py +7 -0
- wagtail/admin/forms/workflows.py +5 -2
- wagtail/admin/icons.py +4 -3
- wagtail/admin/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ar/LC_MESSAGES/django.po +35 -0
- wagtail/admin/locale/en/LC_MESSAGES/django.po +262 -234
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +72 -43
- wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/django.po +566 -6
- wagtail/admin/locale/it/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/djangojs.po +40 -2
- wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/django.po +2 -2
- wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/sv/LC_MESSAGES/django.po +330 -15
- wagtail/admin/locale/sv/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/sv/LC_MESSAGES/djangojs.po +3 -2
- wagtail/admin/panels/comment_panel.py +1 -51
- wagtail/admin/panels/title_field_panel.py +3 -1
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/js/bulk-actions.js +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 -1
- wagtail/admin/static/wagtailadmin/js/draftail.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/wagtailadmin.js +1 -1
- wagtail/admin/templates/wagtailadmin/base.html +1 -1
- wagtail/admin/templates/wagtailadmin/generic/edit_partials.html +100 -0
- wagtail/admin/templates/wagtailadmin/generic/form.html +26 -5
- wagtail/admin/templates/wagtailadmin/generic/includes/_loaded_revision_inputs.html +3 -0
- wagtail/admin/templates/wagtailadmin/generic/listing_results.html +1 -17
- wagtail/admin/templates/wagtailadmin/pages/create.html +14 -4
- wagtail/admin/templates/wagtailadmin/pages/edit.html +16 -3
- wagtail/admin/templates/wagtailadmin/pages/edit_partials.html +31 -0
- wagtail/admin/templates/wagtailadmin/pages/index_results.html +1 -9
- wagtail/admin/templates/wagtailadmin/shared/autosave/indicator.html +36 -0
- wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +19 -3
- wagtail/admin/templates/wagtailadmin/shared/headers/_actions.html +5 -0
- wagtail/admin/templates/wagtailadmin/shared/headers/_history_icon_link.html +2 -2
- wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +8 -9
- wagtail/admin/templates/wagtailadmin/shared/listing/filter_partials.html +19 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +3 -3
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/side_panel.html +3 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/privacy.html +18 -6
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/usage.html +11 -4
- wagtail/admin/templates/wagtailadmin/shared/side_panels/includes/status/workflow.html +22 -1
- wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html +1 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels.html +1 -2
- wagtail/admin/templates/wagtailadmin/shared/unsaved_changes_warning.html +20 -20
- wagtail/admin/templates/wagtailadmin/userbar/base.html +2 -0
- wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +1 -1
- wagtail/admin/templatetags/wagtailadmin_tags.py +6 -14
- wagtail/admin/tests/pages/test_create_page.py +298 -1
- wagtail/admin/tests/pages/test_custom_listing.py +48 -2
- wagtail/admin/tests/pages/test_edit_page.py +721 -7
- wagtail/admin/tests/pages/test_explorer_view.py +9 -5
- wagtail/admin/tests/pages/test_page_search.py +15 -0
- wagtail/admin/tests/pages/test_revisions.py +4 -0
- wagtail/admin/tests/test_account_management.py +88 -2
- wagtail/admin/tests/test_collections_views.py +15 -15
- wagtail/admin/tests/test_compare.py +34 -0
- wagtail/admin/tests/test_editing_sessions.py +230 -8
- wagtail/admin/tests/test_forms.py +192 -1
- wagtail/admin/tests/test_icon_sprite.py +22 -2
- wagtail/admin/tests/test_page_chooser.py +13 -13
- wagtail/admin/tests/test_reports_views.py +4 -1
- wagtail/admin/tests/test_userbar.py +69 -5
- wagtail/admin/tests/test_views_generic.py +5 -5
- wagtail/admin/tests/test_workflows.py +14 -12
- wagtail/admin/tests/viewsets/test_model_viewset.py +13 -0
- wagtail/admin/ui/autosave.py +5 -0
- wagtail/admin/ui/editing_sessions.py +3 -0
- wagtail/admin/ui/side_panels.py +19 -20
- wagtail/admin/userbar.py +48 -27
- wagtail/admin/views/bulk_action/dispatcher.py +2 -2
- wagtail/admin/views/chooser.py +6 -6
- wagtail/admin/views/editing_sessions.py +20 -7
- wagtail/admin/views/generic/__init__.py +1 -0
- wagtail/admin/views/generic/chooser.py +5 -5
- wagtail/admin/views/generic/mixins.py +143 -26
- wagtail/admin/views/generic/models.py +157 -27
- wagtail/admin/views/generic/ordering.py +1 -1
- wagtail/admin/views/generic/preview.py +4 -4
- wagtail/admin/views/home.py +3 -1
- wagtail/admin/views/pages/create.py +77 -29
- wagtail/admin/views/pages/edit.py +160 -34
- wagtail/admin/views/pages/preview.py +4 -4
- wagtail/admin/views/pages/revisions.py +3 -0
- wagtail/admin/views/pages/search.py +4 -4
- wagtail/admin/views/pages/usage.py +2 -2
- wagtail/admin/views/tags.py +2 -2
- wagtail/admin/views/workflows.py +73 -54
- wagtail/admin/viewsets/model.py +34 -8
- wagtail/admin/widgets/button.py +11 -4
- wagtail/admin/widgets/chooser.py +6 -4
- wagtail/admin/widgets/slug.py +1 -1
- wagtail/api/v2/filters.py +27 -21
- wagtail/api/v2/pagination.py +4 -4
- wagtail/api/v2/views.py +7 -7
- wagtail/blocks/list_block.py +0 -8
- wagtail/blocks/migrations/migrate_operation.py +8 -1
- wagtail/blocks/stream_block.py +2 -10
- wagtail/blocks/struct_block.py +192 -12
- wagtail/compat.py +2 -2
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/forms/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/it/LC_MESSAGES/django.po +40 -2
- wagtail/contrib/frontend_cache/backends/azure.py +6 -6
- wagtail/contrib/frontend_cache/backends/cloudfront.py +2 -2
- wagtail/contrib/frontend_cache/utils.py +1 -1
- wagtail/contrib/redirects/forms.py +1 -1
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.po +15 -2
- wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.po +16 -3
- wagtail/contrib/redirects/middleware.py +11 -7
- wagtail/contrib/redirects/models.py +17 -1
- wagtail/contrib/redirects/tests/test_import_admin_views.py +3 -3
- wagtail/contrib/redirects/tests/test_redirects.py +56 -8
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +6 -6
- wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +43 -2
- wagtail/contrib/search_promotions/tests.py +1 -1
- wagtail/contrib/search_promotions/views/settings.py +24 -25
- wagtail/contrib/settings/jinja2tags.py +2 -2
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/contrib/settings/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/it/LC_MESSAGES/django.po +6 -2
- wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/sv/LC_MESSAGES/django.po +3 -2
- wagtail/contrib/settings/tests/generic/test_admin.py +118 -2
- wagtail/contrib/settings/tests/site_specific/test_admin.py +78 -15
- wagtail/contrib/settings/tests/site_specific/test_model.py +2 -2
- wagtail/contrib/settings/views.py +7 -0
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/simple_translation/locale/it/LC_MESSAGES/django.po +5 -2
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
- wagtail/contrib/styleguide/tests.py +2 -0
- wagtail/contrib/styleguide/views.py +4 -5
- wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.po +5 -1
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +5 -2
- wagtail/contrib/typed_table_block/blocks.py +37 -0
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/typed_table_block/locale/sv/LC_MESSAGES/django.po +4 -3
- wagtail/contrib/typed_table_block/tests.py +108 -0
- wagtail/coreutils.py +4 -4
- wagtail/documents/__init__.py +4 -4
- wagtail/documents/locale/en/LC_MESSAGES/django.po +15 -15
- wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/it/LC_MESSAGES/django.po +32 -2
- wagtail/documents/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/sv/LC_MESSAGES/django.po +32 -4
- wagtail/documents/models.py +1 -1
- wagtail/documents/tests/test_admin_views.py +19 -4
- wagtail/documents/tests/test_search.py +0 -2
- wagtail/documents/tests/test_views.py +6 -4
- wagtail/documents/views/bulk_actions/add_tags.py +1 -1
- wagtail/embeds/finders/facebook.py +3 -3
- wagtail/embeds/finders/instagram.py +3 -3
- wagtail/embeds/finders/oembed.py +7 -2
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/oembed_providers.py +8 -0
- wagtail/embeds/tests/test_embeds.py +35 -0
- wagtail/images/__init__.py +4 -4
- wagtail/images/admin_urls.py +3 -3
- wagtail/images/blocks.py +1 -1
- wagtail/images/formats.py +2 -2
- wagtail/images/image_operations.py +2 -2
- wagtail/images/locale/en/LC_MESSAGES/django.po +44 -40
- wagtail/images/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/it/LC_MESSAGES/django.po +50 -4
- wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/nl/LC_MESSAGES/django.po +3 -3
- wagtail/images/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/sv/LC_MESSAGES/django.po +49 -6
- wagtail/images/models.py +11 -10
- wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
- wagtail/images/templates/wagtailimages/images/url_generator.html +17 -38
- wagtail/images/templates/wagtailimages/images/url_generator_output.html +28 -0
- wagtail/images/templatetags/wagtailimages_tags.py +4 -4
- wagtail/images/tests/test_admin_views.py +432 -59
- wagtail/images/tests/test_image_operations.py +2 -2
- wagtail/images/tests/test_models.py +0 -2
- wagtail/images/views/bulk_actions/add_tags.py +1 -1
- wagtail/images/views/images.py +72 -39
- wagtail/locale/en/LC_MESSAGES/django.po +103 -105
- wagtail/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/it/LC_MESSAGES/django.po +105 -2
- wagtail/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/sv/LC_MESSAGES/django.po +95 -12
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/locales/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/it/LC_MESSAGES/django.po +13 -2
- wagtail/locales/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/sv/LC_MESSAGES/django.po +4 -3
- wagtail/locales/tests.py +5 -5
- wagtail/models/i18n.py +4 -6
- wagtail/models/media.py +18 -0
- wagtail/models/pages.py +65 -11
- wagtail/models/reference_index.py +15 -0
- wagtail/models/revisions.py +40 -12
- wagtail/models/workflows.py +0 -3
- wagtail/permission_policies/base.py +2 -2
- wagtail/permission_policies/collections.py +2 -2
- wagtail/project_template/requirements.txt +2 -2
- wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/signal_handlers.py +1 -0
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/sites/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/sites/locale/sv/LC_MESSAGES/django.po +3 -2
- wagtail/sites/tests.py +7 -7
- wagtail/snippets/action_menu.py +2 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +23 -13
- wagtail/snippets/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/sv/LC_MESSAGES/django.po +12 -1
- wagtail/snippets/tests/test_chooser_block.py +197 -0
- wagtail/snippets/tests/test_chooser_panel.py +149 -0
- wagtail/snippets/tests/test_chooser_views.py +375 -0
- wagtail/snippets/tests/test_chooser_widget.py +22 -0
- wagtail/snippets/tests/test_compare_revisions_view.py +167 -0
- wagtail/snippets/tests/test_copy_view.py +38 -0
- wagtail/snippets/tests/test_create_view.py +1159 -0
- wagtail/snippets/tests/test_delete_view.py +225 -0
- wagtail/snippets/tests/test_edit_view.py +2882 -0
- wagtail/snippets/tests/test_history_view.py +182 -0
- wagtail/snippets/tests/test_index_view.py +105 -0
- wagtail/snippets/tests/test_list_view.py +786 -0
- wagtail/snippets/tests/test_locking.py +28 -0
- wagtail/snippets/tests/test_permissions.py +167 -0
- wagtail/snippets/tests/test_preview.py +3 -3
- wagtail/snippets/tests/test_revert_view.py +343 -0
- wagtail/snippets/tests/test_snippet_models.py +112 -0
- wagtail/snippets/tests/test_unpublish_view.py +228 -0
- wagtail/snippets/tests/test_unschedule_view.py +151 -0
- wagtail/snippets/tests/test_viewset.py +38 -5
- wagtail/snippets/views/snippets.py +78 -30
- wagtail/snippets/widgets.py +2 -2
- wagtail/templatetags/wagtailcore_tags.py +2 -2
- wagtail/test/dummy_external_storage.py +1 -1
- wagtail/test/testapp/fixtures/test.json +22 -0
- wagtail/test/testapp/fixtures/test_empty.json +2 -0
- wagtail/test/testapp/fixtures/test_explorable_pages.json +10 -0
- wagtail/test/testapp/fixtures/test_specific.json +9 -0
- wagtail/test/testapp/migrations/0059_nopromotepage.py +25 -0
- wagtail/test/testapp/models.py +7 -0
- wagtail/test/testapp/views.py +5 -0
- wagtail/test/utils/page_tests.py +7 -7
- wagtail/test/utils/wagtail_factories/builder.py +2 -2
- wagtail/tests/streamfield_migrations/test_migrations.py +35 -0
- wagtail/tests/test_blocks.py +321 -61
- wagtail/tests/test_collection_model.py +12 -0
- wagtail/tests/test_page_model.py +190 -1
- wagtail/tests/test_page_privacy.py +5 -0
- wagtail/tests/test_reference_index.py +42 -0
- wagtail/tests/test_revision_model.py +118 -1
- wagtail/tests/test_utils.py +2 -2
- wagtail/users/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/users/locale/id_ID/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/id_ID/LC_MESSAGES/django.po +6 -2
- wagtail/users/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/it/LC_MESSAGES/django.po +14 -2
- wagtail/users/locale/sv/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/sv/LC_MESSAGES/django.po +48 -17
- wagtail/users/tests/test_admin_views.py +39 -25
- wagtail/users/utils.py +4 -1
- wagtail/users/views/groups.py +19 -5
- wagtail/users/wagtail_hooks.py +1 -1
- wagtail/utils/loading.py +2 -2
- wagtail-7.3rc1.data/data/AGENTS.md +21 -0
- wagtail-7.3rc1.data/data/CHANGELOG.txt +4941 -0
- wagtail-7.3rc1.data/data/CODE_OF_CONDUCT.md +71 -0
- wagtail-7.3rc1.data/data/CONTRIBUTORS.md +999 -0
- wagtail-7.3rc1.data/data/SPONSORS.md +55 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/METADATA +6 -6
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/RECORD +310 -280
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/WHEEL +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +0 -1
- wagtail/snippets/tests/test_snippets.py +0 -6377
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/licenses/LICENSE +0 -0
- {wagtail-7.2.1.dist-info → wagtail-7.3rc1.dist-info}/top_level.txt +0 -0
|
@@ -93,12 +93,16 @@ class TestPageExplorer(WagtailTestUtils, TestCase):
|
|
|
93
93
|
count=3,
|
|
94
94
|
)
|
|
95
95
|
|
|
96
|
+
# Should render bulk actions markup
|
|
96
97
|
bulk_actions_js = versioned_static("wagtailadmin/js/bulk-actions.js")
|
|
97
|
-
self.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
)
|
|
98
|
+
soup = self.get_soup(response.content)
|
|
99
|
+
script = soup.select_one(f"script[src='{bulk_actions_js}']")
|
|
100
|
+
self.assertIsNotNone(script)
|
|
101
|
+
bulk_actions = soup.select("[data-bulk-action-button]")
|
|
102
|
+
self.assertTrue(bulk_actions)
|
|
103
|
+
# 'next' parameter is constructed client-side later based on filters state
|
|
104
|
+
for action in bulk_actions:
|
|
105
|
+
self.assertNotIn("next=", action["href"])
|
|
102
106
|
|
|
103
107
|
def test_explore_results(self):
|
|
104
108
|
explore_results_url = reverse(
|
|
@@ -6,6 +6,7 @@ from django.test import TransactionTestCase
|
|
|
6
6
|
from django.urls import reverse
|
|
7
7
|
from django.utils.http import urlencode
|
|
8
8
|
|
|
9
|
+
from wagtail.admin.staticfiles import versioned_static
|
|
9
10
|
from wagtail.models import Page
|
|
10
11
|
from wagtail.test.testapp.models import EventIndex, SimplePage, SingleEventPage
|
|
11
12
|
from wagtail.test.utils import WagtailTestUtils
|
|
@@ -338,3 +339,17 @@ class TestPageSearch(WagtailTestUtils, TransactionTestCase):
|
|
|
338
339
|
response,
|
|
339
340
|
f"{url}?q=&content_type=tests.eventindex",
|
|
340
341
|
)
|
|
342
|
+
|
|
343
|
+
def test_bulk_action_rendered(self):
|
|
344
|
+
response = self.get()
|
|
345
|
+
self.assertEqual(response.status_code, 200)
|
|
346
|
+
# Should render bulk actions markup
|
|
347
|
+
bulk_actions_js = versioned_static("wagtailadmin/js/bulk-actions.js")
|
|
348
|
+
soup = self.get_soup(response.content)
|
|
349
|
+
script = soup.select_one(f"script[src='{bulk_actions_js}']")
|
|
350
|
+
self.assertIsNotNone(script)
|
|
351
|
+
bulk_actions = soup.select("[data-bulk-action-button]")
|
|
352
|
+
self.assertTrue(bulk_actions)
|
|
353
|
+
# 'next' parameter is constructed client-side later based on filters state
|
|
354
|
+
for action in bulk_actions:
|
|
355
|
+
self.assertNotIn("next=", action["href"])
|
|
@@ -130,6 +130,10 @@ class TestRevisions(WagtailTestUtils, TestCase):
|
|
|
130
130
|
args=(self.christmas_event.id, self.last_christmas_revision.id),
|
|
131
131
|
),
|
|
132
132
|
)
|
|
133
|
+
# Autosave should be disabled
|
|
134
|
+
self.assertNotIn("w-autosave", form["data-controller"].split())
|
|
135
|
+
self.assertNotIn("w-autosave", form["data-action"])
|
|
136
|
+
self.assertIsNone(form.attrs.get("data-w-autosave-interval-value"))
|
|
133
137
|
|
|
134
138
|
# Buttons should be relabelled
|
|
135
139
|
self.assertContains(response, "Replace current draft")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import unittest
|
|
2
3
|
import zoneinfo
|
|
3
4
|
|
|
@@ -10,7 +11,9 @@ from django.core import mail
|
|
|
10
11
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
11
12
|
from django.test import RequestFactory, TestCase, override_settings
|
|
12
13
|
from django.urls import reverse
|
|
14
|
+
from PIL import Image
|
|
13
15
|
|
|
16
|
+
from wagtail.admin.forms.account import AvatarPreferencesForm
|
|
14
17
|
from wagtail.admin.localization import (
|
|
15
18
|
WAGTAILADMIN_PROVIDED_LANGUAGES,
|
|
16
19
|
get_available_admin_languages,
|
|
@@ -733,6 +736,23 @@ class TestAccountUploadAvatar(WagtailTestUtils, TestCase, TestAccountSectionUtil
|
|
|
733
736
|
self.avatar = get_test_image_file()
|
|
734
737
|
self.other_avatar = get_test_image_file()
|
|
735
738
|
|
|
739
|
+
def create_image_file(self, size=(800, 800), color="red", name="test.png"):
|
|
740
|
+
img = Image.new("RGB", size, color=color)
|
|
741
|
+
img_byte_arr = io.BytesIO()
|
|
742
|
+
|
|
743
|
+
ext = name.split(".")[-1].upper()
|
|
744
|
+
if ext == "JPG":
|
|
745
|
+
ext = "JPEG"
|
|
746
|
+
|
|
747
|
+
img.save(img_byte_arr, format=ext)
|
|
748
|
+
img_byte_arr.seek(0)
|
|
749
|
+
|
|
750
|
+
content_type = f"image/{ext.lower()}" if ext != "JPEG" else "image/jpeg"
|
|
751
|
+
|
|
752
|
+
return SimpleUploadedFile(
|
|
753
|
+
name=name, content=img_byte_arr.read(), content_type=content_type
|
|
754
|
+
)
|
|
755
|
+
|
|
736
756
|
def test_account_view(self):
|
|
737
757
|
"""
|
|
738
758
|
This tests that the account view renders a "Upload a profile picture" field
|
|
@@ -789,6 +809,7 @@ class TestAccountUploadAvatar(WagtailTestUtils, TestCase, TestAccountSectionUtil
|
|
|
789
809
|
"""
|
|
790
810
|
profile = UserProfile.get_for_user(self.user)
|
|
791
811
|
profile.avatar = self.avatar
|
|
812
|
+
old_url = profile.avatar.url
|
|
792
813
|
profile.save()
|
|
793
814
|
|
|
794
815
|
# Upload a new avatar
|
|
@@ -798,7 +819,8 @@ class TestAccountUploadAvatar(WagtailTestUtils, TestCase, TestAccountSectionUtil
|
|
|
798
819
|
|
|
799
820
|
# Check the avatar was changed
|
|
800
821
|
profile.refresh_from_db()
|
|
801
|
-
self.
|
|
822
|
+
self.assertEqual("/media/test.png", old_url)
|
|
823
|
+
self.assertTrue(profile.avatar.url.endswith(".png"))
|
|
802
824
|
|
|
803
825
|
def test_clear_removes_current_avatar(self):
|
|
804
826
|
"""
|
|
@@ -815,7 +837,71 @@ class TestAccountUploadAvatar(WagtailTestUtils, TestCase, TestAccountSectionUtil
|
|
|
815
837
|
|
|
816
838
|
# Check the avatar was changed
|
|
817
839
|
profile.refresh_from_db()
|
|
818
|
-
self.
|
|
840
|
+
self.assertTrue(profile.avatar)
|
|
841
|
+
|
|
842
|
+
def test_avatar_resize_large_image(self):
|
|
843
|
+
"""Ensure that large uploaded images are resized to a maximum of 400x400."""
|
|
844
|
+
uploaded_file = self.create_image_file(size=(800, 800), name="large_image.jpg")
|
|
845
|
+
form = AvatarPreferencesForm(files={"avatar": uploaded_file})
|
|
846
|
+
self.assertTrue(form.is_valid())
|
|
847
|
+
|
|
848
|
+
avatar_file = form.clean_avatar()
|
|
849
|
+
resized_image = Image.open(avatar_file)
|
|
850
|
+
self.assertLessEqual(resized_image.width, 400)
|
|
851
|
+
self.assertLessEqual(resized_image.height, 400)
|
|
852
|
+
|
|
853
|
+
def test_avatar_no_resize_small_image(self):
|
|
854
|
+
uploaded_file = self.create_image_file(size=(300, 300), name="small_image.jpg")
|
|
855
|
+
form = AvatarPreferencesForm(files={"avatar": uploaded_file})
|
|
856
|
+
self.assertTrue(form.is_valid())
|
|
857
|
+
|
|
858
|
+
avatar_file = form.clean_avatar()
|
|
859
|
+
image = Image.open(avatar_file)
|
|
860
|
+
self.assertEqual(image.size, (300, 300))
|
|
861
|
+
|
|
862
|
+
def test_avatar_resize_width_greater_than_height(self):
|
|
863
|
+
uploaded_file = self.create_image_file(size=(500, 300), name="wide_image.jpg")
|
|
864
|
+
form = AvatarPreferencesForm(files={"avatar": uploaded_file})
|
|
865
|
+
self.assertTrue(form.is_valid())
|
|
866
|
+
|
|
867
|
+
avatar_file = form.clean_avatar()
|
|
868
|
+
resized_image = Image.open(avatar_file)
|
|
869
|
+
self.assertEqual(resized_image.size, (400, 240))
|
|
870
|
+
|
|
871
|
+
original_ratio = 500 / 300
|
|
872
|
+
new_ratio = resized_image.width / resized_image.height
|
|
873
|
+
self.assertAlmostEqual(original_ratio, new_ratio, places=2)
|
|
874
|
+
|
|
875
|
+
def test_avatar_resize_height_greater_than_width(self):
|
|
876
|
+
uploaded_file = self.create_image_file(size=(300, 500), name="tall_image.jpg")
|
|
877
|
+
form = AvatarPreferencesForm(files={"avatar": uploaded_file})
|
|
878
|
+
self.assertTrue(form.is_valid())
|
|
879
|
+
|
|
880
|
+
avatar_file = form.clean_avatar()
|
|
881
|
+
resized_image = Image.open(avatar_file)
|
|
882
|
+
self.assertEqual(resized_image.size, (240, 400))
|
|
883
|
+
|
|
884
|
+
original_ratio = 300 / 500
|
|
885
|
+
new_ratio = resized_image.width / resized_image.height
|
|
886
|
+
self.assertAlmostEqual(original_ratio, new_ratio, places=2)
|
|
887
|
+
|
|
888
|
+
def test_avatar_preserves_original_format(self):
|
|
889
|
+
# Test JPG format
|
|
890
|
+
jpg_file = self.create_image_file(size=(500, 500), name="test.jpg")
|
|
891
|
+
form = AvatarPreferencesForm(files={"avatar": jpg_file})
|
|
892
|
+
self.assertTrue(form.is_valid())
|
|
893
|
+
avatar_file = form.clean_avatar()
|
|
894
|
+
self.assertTrue(avatar_file.name.endswith(".jpg"))
|
|
895
|
+
|
|
896
|
+
# Test PNG format
|
|
897
|
+
png_file = self.create_image_file(size=(500, 500), name="test.png")
|
|
898
|
+
form = AvatarPreferencesForm(files={"avatar": png_file})
|
|
899
|
+
self.assertTrue(form.is_valid())
|
|
900
|
+
avatar_file = form.clean_avatar()
|
|
901
|
+
self.assertTrue(avatar_file.name.endswith(".png"))
|
|
902
|
+
|
|
903
|
+
resized_image = Image.open(avatar_file)
|
|
904
|
+
self.assertIsNotNone(resized_image.format)
|
|
819
905
|
|
|
820
906
|
|
|
821
907
|
class TestAccountManagementForNonModerator(WagtailTestUtils, TestCase):
|
|
@@ -55,7 +55,7 @@ class TestCollectionsIndexViewAsSuperuser(
|
|
|
55
55
|
def setUp(self):
|
|
56
56
|
self.login()
|
|
57
57
|
|
|
58
|
-
def get(self, params=
|
|
58
|
+
def get(self, params=None):
|
|
59
59
|
return self.client.get(reverse("wagtailadmin_collections:index"), params)
|
|
60
60
|
|
|
61
61
|
def test_simple(self):
|
|
@@ -118,7 +118,7 @@ class TestCollectionsIndexView(CollectionInstanceTestUtils, WagtailTestUtils, Te
|
|
|
118
118
|
super().setUp()
|
|
119
119
|
self.login(self.marketing_user, password="password")
|
|
120
120
|
|
|
121
|
-
def get(self, params=
|
|
121
|
+
def get(self, params=None):
|
|
122
122
|
return self.client.get(reverse("wagtailadmin_collections:index"), params)
|
|
123
123
|
|
|
124
124
|
def test_marketing_user_no_permissions(self):
|
|
@@ -203,10 +203,10 @@ class TestAddCollectionAsSuperuser(AdminTemplateTestUtils, WagtailTestUtils, Tes
|
|
|
203
203
|
self.login()
|
|
204
204
|
self.root_collection = Collection.get_first_root_node()
|
|
205
205
|
|
|
206
|
-
def get(self, params=
|
|
206
|
+
def get(self, params=None):
|
|
207
207
|
return self.client.get(reverse("wagtailadmin_collections:add"), params)
|
|
208
208
|
|
|
209
|
-
def post(self, post_data=
|
|
209
|
+
def post(self, post_data=None):
|
|
210
210
|
return self.client.post(reverse("wagtailadmin_collections:add"), post_data)
|
|
211
211
|
|
|
212
212
|
def test_get(self):
|
|
@@ -245,10 +245,10 @@ class TestAddCollection(CollectionInstanceTestUtils, WagtailTestUtils, TestCase)
|
|
|
245
245
|
super().setUp()
|
|
246
246
|
self.login(self.marketing_user, password="password")
|
|
247
247
|
|
|
248
|
-
def get(self, params=
|
|
248
|
+
def get(self, params=None):
|
|
249
249
|
return self.client.get(reverse("wagtailadmin_collections:add"), params)
|
|
250
250
|
|
|
251
|
-
def post(self, post_data=
|
|
251
|
+
def post(self, post_data=None):
|
|
252
252
|
return self.client.post(reverse("wagtailadmin_collections:add"), post_data)
|
|
253
253
|
|
|
254
254
|
def test_marketing_user_no_permissions(self):
|
|
@@ -316,7 +316,7 @@ class TestEditCollectionAsSuperuser(AdminTemplateTestUtils, WagtailTestUtils, Te
|
|
|
316
316
|
self.l2 = self.l1.add_child(name="Level 2")
|
|
317
317
|
self.l3 = self.l2.add_child(name="Level 3")
|
|
318
318
|
|
|
319
|
-
def get(self, params=
|
|
319
|
+
def get(self, params=None, collection_id=None):
|
|
320
320
|
return self.client.get(
|
|
321
321
|
reverse(
|
|
322
322
|
"wagtailadmin_collections:edit",
|
|
@@ -325,7 +325,7 @@ class TestEditCollectionAsSuperuser(AdminTemplateTestUtils, WagtailTestUtils, Te
|
|
|
325
325
|
params,
|
|
326
326
|
)
|
|
327
327
|
|
|
328
|
-
def post(self, post_data=
|
|
328
|
+
def post(self, post_data=None, collection_id=None):
|
|
329
329
|
return self.client.post(
|
|
330
330
|
reverse(
|
|
331
331
|
"wagtailadmin_collections:edit",
|
|
@@ -408,12 +408,12 @@ class TestEditCollection(CollectionInstanceTestUtils, WagtailTestUtils, TestCase
|
|
|
408
408
|
)
|
|
409
409
|
self.login(self.marketing_user, password="password")
|
|
410
410
|
|
|
411
|
-
def get(self, collection_id, params=
|
|
411
|
+
def get(self, collection_id, params=None):
|
|
412
412
|
return self.client.get(
|
|
413
413
|
reverse("wagtailadmin_collections:edit", args=(collection_id,)), params
|
|
414
414
|
)
|
|
415
415
|
|
|
416
|
-
def post(self, collection_id, post_data=
|
|
416
|
+
def post(self, collection_id, post_data=None):
|
|
417
417
|
return self.client.post(
|
|
418
418
|
reverse("wagtailadmin_collections:edit", args=(collection_id,)), post_data
|
|
419
419
|
)
|
|
@@ -598,7 +598,7 @@ class TestDeleteCollectionAsSuperuser(
|
|
|
598
598
|
self.root_collection = Collection.get_first_root_node()
|
|
599
599
|
self.collection = self.root_collection.add_child(name="Holiday snaps")
|
|
600
600
|
|
|
601
|
-
def get(self, params=
|
|
601
|
+
def get(self, params=None, collection_id=None):
|
|
602
602
|
return self.client.get(
|
|
603
603
|
reverse(
|
|
604
604
|
"wagtailadmin_collections:delete",
|
|
@@ -607,7 +607,7 @@ class TestDeleteCollectionAsSuperuser(
|
|
|
607
607
|
params,
|
|
608
608
|
)
|
|
609
609
|
|
|
610
|
-
def post(self, post_data=
|
|
610
|
+
def post(self, post_data=None, collection_id=None):
|
|
611
611
|
return self.client.post(
|
|
612
612
|
reverse(
|
|
613
613
|
"wagtailadmin_collections:delete",
|
|
@@ -703,12 +703,12 @@ class TestDeleteCollection(CollectionInstanceTestUtils, WagtailTestUtils, TestCa
|
|
|
703
703
|
)
|
|
704
704
|
self.login(self.marketing_user, password="password")
|
|
705
705
|
|
|
706
|
-
def get(self, collection_id, params=
|
|
706
|
+
def get(self, collection_id, params=None):
|
|
707
707
|
return self.client.get(
|
|
708
708
|
reverse("wagtailadmin_collections:delete", args=(collection_id,)), params
|
|
709
709
|
)
|
|
710
710
|
|
|
711
|
-
def post(self, collection_id, post_data=
|
|
711
|
+
def post(self, collection_id, post_data=None):
|
|
712
712
|
return self.client.post(
|
|
713
713
|
reverse("wagtailadmin_collections:delete", args=(collection_id,)), post_data
|
|
714
714
|
)
|
|
@@ -775,7 +775,7 @@ class TestSetCollectionPrivacy(CollectionInstanceTestUtils, WagtailTestUtils, Te
|
|
|
775
775
|
super().setUp()
|
|
776
776
|
self.login()
|
|
777
777
|
|
|
778
|
-
def get(self, collection_id, params=
|
|
778
|
+
def get(self, collection_id, params=None):
|
|
779
779
|
return self.client.get(
|
|
780
780
|
reverse("wagtailadmin_collections:set_privacy", args=(collection_id,)),
|
|
781
781
|
params,
|
|
@@ -921,6 +921,40 @@ class TestStreamFieldComparison(TestCase):
|
|
|
921
921
|
self.assertTrue(comparison.has_changed())
|
|
922
922
|
|
|
923
923
|
|
|
924
|
+
class TestStreamBlockComparison(TestCase):
|
|
925
|
+
comparison_class = compare.StreamBlockComparison
|
|
926
|
+
|
|
927
|
+
def test_streamblock_comparison_htmlvalue(self):
|
|
928
|
+
field = StreamPage._meta.get_field("body")
|
|
929
|
+
stream_block = field.stream_block.child_blocks["books"]
|
|
930
|
+
|
|
931
|
+
stream_value = StreamValue(
|
|
932
|
+
stream_block,
|
|
933
|
+
[
|
|
934
|
+
("title", "Test Title", "1"),
|
|
935
|
+
("author", "Test Author", "2"),
|
|
936
|
+
],
|
|
937
|
+
)
|
|
938
|
+
|
|
939
|
+
comparison = self.comparison_class(
|
|
940
|
+
stream_block,
|
|
941
|
+
True,
|
|
942
|
+
True,
|
|
943
|
+
stream_value,
|
|
944
|
+
stream_value,
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
result = comparison.htmlvalue(stream_value)
|
|
948
|
+
|
|
949
|
+
self.assertIsInstance(result, SafeString)
|
|
950
|
+
self.assertIn("<dl>", result)
|
|
951
|
+
self.assertIn("</dl>", result)
|
|
952
|
+
self.assertIn("<dt>Title</dt>", result)
|
|
953
|
+
self.assertIn("<dt>Author</dt>", result)
|
|
954
|
+
self.assertIn("<dd>Test Title</dd>", result)
|
|
955
|
+
self.assertIn("<dd>Test Author</dd>", result)
|
|
956
|
+
|
|
957
|
+
|
|
924
958
|
class TestChoiceFieldComparison(TestCase):
|
|
925
959
|
comparison_class = compare.ChoiceFieldComparison
|
|
926
960
|
|
|
@@ -282,12 +282,16 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
282
282
|
self.assertIn("Vic Otheruser saved a new version", session_text)
|
|
283
283
|
self.assertNotIn("Currently viewing", session_text)
|
|
284
284
|
dialog_title = soup.select_one(
|
|
285
|
-
|
|
285
|
+
"template"
|
|
286
|
+
'[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
287
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
286
288
|
)
|
|
287
289
|
self.assertIsNotNone(dialog_title)
|
|
288
290
|
self.assertIn("Vic Otheruser saved a new version", dialog_title.string)
|
|
289
291
|
dialog_subtitle = soup.select_one(
|
|
290
|
-
|
|
292
|
+
"template"
|
|
293
|
+
'[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
294
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
291
295
|
)
|
|
292
296
|
self.assertIsNotNone(dialog_subtitle)
|
|
293
297
|
self.assertIn(
|
|
@@ -328,6 +332,179 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
328
332
|
],
|
|
329
333
|
)
|
|
330
334
|
|
|
335
|
+
soup = self.get_soup(response_json["html"])
|
|
336
|
+
rendered_sessions = soup.select("ol.w-editing-sessions__list li")
|
|
337
|
+
self.assertEqual(len(rendered_sessions), 1)
|
|
338
|
+
session_text = rendered_sessions[0].text
|
|
339
|
+
self.assertIn("Vic Otheruser saved a new version", session_text)
|
|
340
|
+
self.assertNotIn("Currently viewing", session_text)
|
|
341
|
+
dialog_title = soup.select_one(
|
|
342
|
+
"template"
|
|
343
|
+
'[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
344
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
345
|
+
)
|
|
346
|
+
self.assertIsNotNone(dialog_title)
|
|
347
|
+
self.assertIn(
|
|
348
|
+
"Vic Otheruser saved a new version",
|
|
349
|
+
dialog_title.string,
|
|
350
|
+
)
|
|
351
|
+
dialog_subtitle = soup.select_one(
|
|
352
|
+
"template"
|
|
353
|
+
'[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
354
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
355
|
+
)
|
|
356
|
+
self.assertIsNotNone(dialog_subtitle)
|
|
357
|
+
self.assertIn(
|
|
358
|
+
"Proceeding will overwrite the changes made by Vic Otheruser. "
|
|
359
|
+
"Refreshing the page will show you the new changes, but you will lose any of your unsaved changes.",
|
|
360
|
+
dialog_subtitle.string,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
self.session.refresh_from_db()
|
|
364
|
+
self.assertEqual(self.session.last_seen_at, TIMESTAMP_NOW)
|
|
365
|
+
self.assertFalse(self.session.is_editing)
|
|
366
|
+
|
|
367
|
+
@freeze_time(TIMESTAMP_NOW)
|
|
368
|
+
def test_ping_with_overwritten_revision(self):
|
|
369
|
+
# Simulate other user creating a new revision to be used for autosave
|
|
370
|
+
with freeze_time(TIMESTAMP_1):
|
|
371
|
+
loaded_revision = self.page.save_revision(user=self.other_user)
|
|
372
|
+
|
|
373
|
+
loaded_timestamp = loaded_revision.created_at.isoformat()
|
|
374
|
+
response = self.client.post(
|
|
375
|
+
reverse(
|
|
376
|
+
"wagtailadmin_editing_sessions:ping",
|
|
377
|
+
args=("wagtailcore", "page", self.page.id, self.session.id),
|
|
378
|
+
),
|
|
379
|
+
{
|
|
380
|
+
"revision_id": self.original_revision.id,
|
|
381
|
+
"revision_created_at": loaded_timestamp,
|
|
382
|
+
},
|
|
383
|
+
)
|
|
384
|
+
self.assertEqual(response.status_code, 200)
|
|
385
|
+
response_json = response.json()
|
|
386
|
+
self.assertEqual(response_json["session_id"], self.session.id)
|
|
387
|
+
|
|
388
|
+
# no revisions have been saved since the original revision
|
|
389
|
+
self.assertEqual(
|
|
390
|
+
response_json["other_sessions"],
|
|
391
|
+
[
|
|
392
|
+
{
|
|
393
|
+
"session_id": self.other_session.id,
|
|
394
|
+
"user": "Vic Otheruser",
|
|
395
|
+
"last_seen_at": TIMESTAMP_2.isoformat(),
|
|
396
|
+
"is_editing": False,
|
|
397
|
+
"revision_id": None,
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
soup = self.get_soup(response_json["html"])
|
|
403
|
+
rendered_sessions = soup.select("ol.w-editing-sessions__list li")
|
|
404
|
+
self.assertEqual(len(rendered_sessions), 1)
|
|
405
|
+
session_text = rendered_sessions[0].text
|
|
406
|
+
self.assertIn("Vic Otheruser", session_text)
|
|
407
|
+
self.assertIn("Currently viewing", session_text)
|
|
408
|
+
self.assertNotIn("saved a new version", session_text)
|
|
409
|
+
|
|
410
|
+
self.session.refresh_from_db()
|
|
411
|
+
self.assertEqual(self.session.last_seen_at, TIMESTAMP_NOW)
|
|
412
|
+
self.assertFalse(self.session.is_editing)
|
|
413
|
+
|
|
414
|
+
# Simulate other user doing an autosave by overwriting the same revision
|
|
415
|
+
# that we have loaded
|
|
416
|
+
with freeze_time(TIMESTAMP_3):
|
|
417
|
+
self.page.save_revision(
|
|
418
|
+
user=self.other_user,
|
|
419
|
+
overwrite_revision=loaded_revision,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
response = self.client.post(
|
|
423
|
+
reverse(
|
|
424
|
+
"wagtailadmin_editing_sessions:ping",
|
|
425
|
+
args=("wagtailcore", "page", self.page.id, self.session.id),
|
|
426
|
+
),
|
|
427
|
+
{
|
|
428
|
+
"revision_id": self.original_revision.id,
|
|
429
|
+
"revision_created_at": loaded_timestamp,
|
|
430
|
+
},
|
|
431
|
+
)
|
|
432
|
+
self.assertEqual(response.status_code, 200)
|
|
433
|
+
response_json = response.json()
|
|
434
|
+
self.assertEqual(response_json["session_id"], self.session.id)
|
|
435
|
+
|
|
436
|
+
# the overwritten revision should be indicated in the response
|
|
437
|
+
# (and last_seen_at should reflect it), even though it has the same ID
|
|
438
|
+
# as the loaded revision
|
|
439
|
+
self.assertEqual(
|
|
440
|
+
response_json["other_sessions"],
|
|
441
|
+
[
|
|
442
|
+
{
|
|
443
|
+
"session_id": self.other_session.id,
|
|
444
|
+
"user": "Vic Otheruser",
|
|
445
|
+
"last_seen_at": TIMESTAMP_3.isoformat(),
|
|
446
|
+
"is_editing": False,
|
|
447
|
+
"revision_id": loaded_revision.id,
|
|
448
|
+
},
|
|
449
|
+
],
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
soup = self.get_soup(response_json["html"])
|
|
453
|
+
rendered_sessions = soup.select("ol.w-editing-sessions__list li")
|
|
454
|
+
self.assertEqual(len(rendered_sessions), 1)
|
|
455
|
+
session_text = rendered_sessions[0].text
|
|
456
|
+
self.assertIn("Vic Otheruser saved a new version", session_text)
|
|
457
|
+
self.assertNotIn("Currently viewing", session_text)
|
|
458
|
+
dialog_title = soup.select_one(
|
|
459
|
+
'template[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
460
|
+
)
|
|
461
|
+
self.assertIsNotNone(dialog_title)
|
|
462
|
+
self.assertIn("Vic Otheruser saved a new version", dialog_title.string)
|
|
463
|
+
dialog_subtitle = soup.select_one(
|
|
464
|
+
'template[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
465
|
+
)
|
|
466
|
+
self.assertIsNotNone(dialog_subtitle)
|
|
467
|
+
self.assertIn(
|
|
468
|
+
"Proceeding will overwrite the changes made by Vic Otheruser. "
|
|
469
|
+
"Refreshing the page will show you the new changes, but you will lose any of your unsaved changes.",
|
|
470
|
+
dialog_subtitle.string,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
self.session.refresh_from_db()
|
|
474
|
+
self.assertEqual(self.session.last_seen_at, TIMESTAMP_NOW)
|
|
475
|
+
self.assertFalse(self.session.is_editing)
|
|
476
|
+
|
|
477
|
+
self.other_session.delete()
|
|
478
|
+
|
|
479
|
+
response = self.client.post(
|
|
480
|
+
reverse(
|
|
481
|
+
"wagtailadmin_editing_sessions:ping",
|
|
482
|
+
args=("wagtailcore", "page", self.page.id, self.session.id),
|
|
483
|
+
),
|
|
484
|
+
{
|
|
485
|
+
"revision_id": self.original_revision.id,
|
|
486
|
+
"revision_created_at": loaded_timestamp,
|
|
487
|
+
},
|
|
488
|
+
)
|
|
489
|
+
self.assertEqual(response.status_code, 200)
|
|
490
|
+
response_json = response.json()
|
|
491
|
+
self.assertEqual(response_json["session_id"], self.session.id)
|
|
492
|
+
|
|
493
|
+
# the overwritten revision should still appear as an "other session" in
|
|
494
|
+
# the response, even though the editing session record has been deleted
|
|
495
|
+
self.assertEqual(
|
|
496
|
+
response_json["other_sessions"],
|
|
497
|
+
[
|
|
498
|
+
{
|
|
499
|
+
"session_id": None,
|
|
500
|
+
"user": "Vic Otheruser",
|
|
501
|
+
"last_seen_at": TIMESTAMP_3.isoformat(),
|
|
502
|
+
"is_editing": False,
|
|
503
|
+
"revision_id": loaded_revision.id,
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
)
|
|
507
|
+
|
|
331
508
|
soup = self.get_soup(response_json["html"])
|
|
332
509
|
rendered_sessions = soup.select("ol.w-editing-sessions__list li")
|
|
333
510
|
self.assertEqual(len(rendered_sessions), 1)
|
|
@@ -417,7 +594,9 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
417
594
|
self.assertIn("Gordon Thirduser saved a new version", session_text)
|
|
418
595
|
self.assertNotIn("Currently viewing", session_text)
|
|
419
596
|
dialog_title = soup.select_one(
|
|
420
|
-
|
|
597
|
+
"template"
|
|
598
|
+
'[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
599
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
421
600
|
)
|
|
422
601
|
self.assertIsNotNone(dialog_title)
|
|
423
602
|
self.assertIn(
|
|
@@ -425,7 +604,9 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
425
604
|
dialog_title.string,
|
|
426
605
|
)
|
|
427
606
|
dialog_subtitle = soup.select_one(
|
|
428
|
-
|
|
607
|
+
"template"
|
|
608
|
+
'[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
609
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
429
610
|
)
|
|
430
611
|
self.assertIsNotNone(dialog_subtitle)
|
|
431
612
|
self.assertIn(
|
|
@@ -487,7 +668,9 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
487
668
|
self.assertIn("System saved a new version", session_text)
|
|
488
669
|
self.assertNotIn("Currently viewing", session_text)
|
|
489
670
|
dialog_title = soup.select_one(
|
|
490
|
-
|
|
671
|
+
"template"
|
|
672
|
+
'[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
673
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
491
674
|
)
|
|
492
675
|
self.assertIsNotNone(dialog_title)
|
|
493
676
|
self.assertIn(
|
|
@@ -495,7 +678,9 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
495
678
|
dialog_title.string,
|
|
496
679
|
)
|
|
497
680
|
dialog_subtitle = soup.select_one(
|
|
498
|
-
|
|
681
|
+
"template"
|
|
682
|
+
'[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
683
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
499
684
|
)
|
|
500
685
|
self.assertIsNotNone(dialog_subtitle)
|
|
501
686
|
self.assertIn(
|
|
@@ -730,11 +915,15 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
730
915
|
self.assertIn("You have unsaved changes in another window", session_text)
|
|
731
916
|
self.assertNotIn("Currently viewing", session_text)
|
|
732
917
|
dialog_title = soup.select_one(
|
|
733
|
-
|
|
918
|
+
"template"
|
|
919
|
+
'[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
920
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
734
921
|
)
|
|
735
922
|
self.assertIsNone(dialog_title)
|
|
736
923
|
dialog_subtitle = soup.select_one(
|
|
737
|
-
|
|
924
|
+
"template"
|
|
925
|
+
'[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
926
|
+
'[data-w-teleport-mode-value="textContent"]'
|
|
738
927
|
)
|
|
739
928
|
self.assertIsNone(dialog_subtitle)
|
|
740
929
|
other_session_text = rendered_sessions[1].text
|
|
@@ -937,6 +1126,32 @@ class TestPingView(WagtailTestUtils, TestCase):
|
|
|
937
1126
|
],
|
|
938
1127
|
)
|
|
939
1128
|
|
|
1129
|
+
# The rendered HTML should use special messaging if the newer revision
|
|
1130
|
+
# is made by the same user ("in another window").
|
|
1131
|
+
soup = self.get_soup(response_json["html"])
|
|
1132
|
+
rendered_sessions = soup.select("ol.w-editing-sessions__list li")
|
|
1133
|
+
self.assertEqual(len(rendered_sessions), 2)
|
|
1134
|
+
session_text = rendered_sessions[0].text
|
|
1135
|
+
self.assertIn("You saved a new version in another window", session_text)
|
|
1136
|
+
self.assertNotIn("Currently viewing", session_text)
|
|
1137
|
+
dialog_title = soup.select_one(
|
|
1138
|
+
'template[data-w-teleport-target-value="#title-text-w-overwrite-changes-dialog"]'
|
|
1139
|
+
)
|
|
1140
|
+
self.assertIsNotNone(dialog_title)
|
|
1141
|
+
self.assertIn(
|
|
1142
|
+
"You saved a new version in another window", dialog_title.text.strip()
|
|
1143
|
+
)
|
|
1144
|
+
dialog_subtitle = soup.select_one(
|
|
1145
|
+
'template[data-w-teleport-target-value="#subtitle-w-overwrite-changes-dialog"]'
|
|
1146
|
+
)
|
|
1147
|
+
self.assertIsNotNone(dialog_subtitle)
|
|
1148
|
+
self.assertIn(
|
|
1149
|
+
"Proceeding will overwrite the changes you made in that window. "
|
|
1150
|
+
"Refreshing the page will show you the new changes, but you will "
|
|
1151
|
+
"lose any of your unsaved changes in the current window.",
|
|
1152
|
+
dialog_subtitle.text.strip(),
|
|
1153
|
+
)
|
|
1154
|
+
|
|
940
1155
|
@freeze_time(TIMESTAMP_NOW)
|
|
941
1156
|
def test_user_must_have_edit_permission_on_page(self):
|
|
942
1157
|
# make user a member of Editors
|
|
@@ -1331,6 +1546,13 @@ class TestModuleInEditView(WagtailTestUtils, TestCase):
|
|
|
1331
1546
|
revision_input.get("value"),
|
|
1332
1547
|
str(self.object.latest_revision.id),
|
|
1333
1548
|
)
|
|
1549
|
+
revision_created_at = soup.select_one('input[name="revision_created_at"]')
|
|
1550
|
+
self.assertIsNotNone(revision_created_at)
|
|
1551
|
+
self.assertEqual(revision_created_at.get("type"), "hidden")
|
|
1552
|
+
self.assertEqual(
|
|
1553
|
+
revision_created_at.get("value"),
|
|
1554
|
+
self.object.latest_revision.created_at.isoformat(),
|
|
1555
|
+
)
|
|
1334
1556
|
|
|
1335
1557
|
@freeze_time(TIMESTAMP_NOW)
|
|
1336
1558
|
def test_edit_view_with_default_interval(self):
|