wagtail 6.1.3__py3-none-any.whl → 6.2rc1__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 +15 -1
- wagtail/admin/checks.py +20 -30
- wagtail/admin/forms/pages.py +10 -0
- wagtail/admin/icons.py +43 -0
- wagtail/admin/locale/en/LC_MESSAGES/django.po +405 -295
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +21 -3
- wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/sl/LC_MESSAGES/django.po +30 -0
- wagtail/admin/menu.py +2 -2
- wagtail/admin/migrations/0004_editingsession.py +57 -0
- wagtail/admin/migrations/0005_editingsession_is_editing.py +18 -0
- wagtail/admin/models.py +36 -3
- wagtail/admin/rich_text/editors/draftail/__init__.py +2 -20
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget.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/date-time-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/expanding-formset.js +1 -1
- wagtail/admin/static/wagtailadmin/js/filtered-select.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/page-chooser-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/preview-panel.js +2 -1
- wagtail/admin/static/wagtailadmin/js/preview-panel.js.LICENSE.txt +11 -0
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +2 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +11 -0
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +0 -12
- wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
- wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
- wagtail/admin/templates/wagtailadmin/collection_privacy/ancestor_privacy.html +2 -6
- wagtail/admin/templates/wagtailadmin/generic/index_results.html +1 -17
- wagtail/admin/templates/wagtailadmin/generic/listing_results.html +20 -1
- wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +2 -11
- wagtail/admin/templates/wagtailadmin/page_privacy/ancestor_privacy.html +2 -6
- wagtail/admin/templates/wagtailadmin/page_privacy/no_privacy.html +2 -0
- wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -1
- wagtail/admin/templates/wagtailadmin/pages/action_menu/menu.html +1 -1
- wagtail/admin/templates/wagtailadmin/reports/aging_pages_results.html +54 -0
- wagtail/admin/templates/wagtailadmin/reports/base_page_report.html +1 -17
- wagtail/admin/templates/wagtailadmin/reports/base_page_report_results.html +10 -0
- wagtail/admin/templates/wagtailadmin/reports/base_report.html +1 -40
- wagtail/admin/templates/wagtailadmin/reports/base_report_results.html +1 -0
- wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_report.html +21 -27
- wagtail/admin/templates/wagtailadmin/reports/listing/_list_page_types_usage.html +48 -54
- wagtail/admin/templates/wagtailadmin/reports/{locked_pages.html → locked_pages_results.html} +3 -3
- wagtail/admin/templates/wagtailadmin/reports/page_types_usage_results.html +10 -0
- wagtail/admin/templates/wagtailadmin/reports/site_history_results.html +53 -0
- wagtail/admin/templates/wagtailadmin/reports/workflow_results.html +74 -0
- wagtail/admin/templates/wagtailadmin/reports/workflow_tasks_results.html +56 -0
- wagtail/admin/templates/wagtailadmin/shared/_workflow_init.html +8 -44
- wagtail/admin/templates/wagtailadmin/shared/avatar.html +11 -1
- wagtail/admin/templates/wagtailadmin/shared/dialog/dialog.html +5 -4
- wagtail/admin/templates/wagtailadmin/shared/dropdown/dropdown_button.html +2 -1
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/list.html +132 -0
- wagtail/admin/templates/wagtailadmin/shared/editing_sessions/module.html +44 -0
- wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +7 -1
- wagtail/admin/templates/wagtailadmin/shared/page_status_tag_new.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +32 -16
- wagtail/admin/templates/wagtailadmin/skeleton.html +1 -1
- wagtail/admin/templates/wagtailadmin/userbar/item_accessibility.html +9 -11
- wagtail/admin/templatetags/wagtailadmin_tags.py +13 -2
- wagtail/admin/tests/formats/en/__init__.py +0 -0
- wagtail/admin/tests/formats/en/formats.py +1 -0
- wagtail/admin/tests/pages/test_create_page.py +47 -0
- wagtail/admin/tests/pages/test_edit_page.py +10 -8
- wagtail/admin/tests/pages/test_parent_page_chooser_view.py +45 -1
- wagtail/admin/tests/test_checks.py +53 -3
- wagtail/admin/tests/test_collections_views.py +62 -1
- wagtail/admin/tests/test_edit_handlers.py +37 -0
- wagtail/admin/tests/test_editing_sessions.py +1336 -0
- wagtail/admin/tests/test_icon_sprite.py +12 -21
- wagtail/admin/tests/test_page_chooser.py +309 -7
- wagtail/admin/tests/test_privacy.py +82 -0
- wagtail/admin/tests/test_reports_views.py +464 -70
- wagtail/admin/tests/test_userbar.py +93 -6
- wagtail/admin/tests/test_workflows.py +223 -33
- wagtail/admin/tests/viewsets/test_model_viewset.py +151 -2
- wagtail/admin/ui/editing_sessions.py +57 -0
- wagtail/admin/urls/__init__.py +9 -15
- wagtail/admin/urls/editing_sessions.py +17 -0
- wagtail/admin/urls/reports.py +33 -1
- wagtail/admin/userbar.py +77 -20
- wagtail/admin/views/chooser.py +49 -22
- wagtail/admin/views/collections.py +0 -11
- wagtail/admin/views/editing_sessions.py +193 -0
- wagtail/admin/views/generic/__init__.py +1 -0
- wagtail/admin/views/generic/history.py +9 -3
- wagtail/admin/views/generic/mixins.py +44 -3
- wagtail/admin/views/generic/models.py +46 -72
- wagtail/admin/views/generic/permissions.py +20 -10
- wagtail/admin/views/home.py +2 -31
- wagtail/admin/views/page_privacy.py +20 -5
- wagtail/admin/views/pages/choose_parent.py +62 -0
- wagtail/admin/views/pages/edit.py +28 -0
- wagtail/admin/views/reports/aging_pages.py +6 -10
- wagtail/admin/views/reports/audit_logging.py +13 -42
- wagtail/admin/views/reports/base.py +31 -4
- wagtail/admin/views/reports/locked_pages.py +5 -8
- wagtail/admin/views/reports/page_types_usage.py +6 -10
- wagtail/admin/views/reports/workflows.py +36 -12
- wagtail/admin/viewsets/base.py +8 -3
- wagtail/admin/viewsets/chooser.py +1 -1
- wagtail/admin/viewsets/model.py +26 -1
- wagtail/admin/wagtail_hooks.py +2 -1
- wagtail/api/v2/filters.py +6 -0
- wagtail/api/v2/tests/test_documents.py +1 -1
- wagtail/api/v2/tests/test_images.py +1 -1
- wagtail/api/v2/tests/test_pages.py +11 -1
- wagtail/api/v2/utils.py +2 -2
- wagtail/blocks/base.py +35 -12
- wagtail/blocks/definition_lookup.py +85 -0
- wagtail/blocks/list_block.py +12 -0
- wagtail/blocks/migrations/migrate_operation.py +2 -0
- wagtail/blocks/stream_block.py +19 -0
- wagtail/blocks/struct_block.py +19 -0
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/frontend_cache/backends/__init__.py +5 -0
- wagtail/contrib/frontend_cache/backends/azure.py +179 -0
- wagtail/contrib/frontend_cache/backends/base.py +28 -0
- wagtail/contrib/frontend_cache/backends/cloudflare.py +114 -0
- wagtail/contrib/frontend_cache/backends/cloudfront.py +99 -0
- wagtail/contrib/frontend_cache/backends/http.py +64 -0
- wagtail/contrib/frontend_cache/tests.py +59 -17
- wagtail/contrib/frontend_cache/utils.py +26 -8
- wagtail/contrib/redirects/filters.py +15 -1
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +37 -72
- wagtail/contrib/redirects/models.py +6 -5
- wagtail/contrib/redirects/templates/wagtailredirects/edit.html +1 -38
- wagtail/contrib/redirects/tests/test_redirects.py +141 -1
- wagtail/contrib/redirects/urls.py +1 -2
- wagtail/contrib/redirects/views.py +39 -80
- wagtail/contrib/routable_page/models.py +6 -4
- wagtail/contrib/routable_page/tests.py +11 -0
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +4 -4
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +5 -1
- wagtail/contrib/simple_translation/models.py +2 -1
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
- wagtail/contrib/typed_table_block/blocks.py +19 -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 +38 -0
- wagtail/coreutils.py +1 -1
- wagtail/documents/__init__.py +1 -1
- wagtail/documents/locale/en/LC_MESSAGES/django.po +8 -8
- wagtail/documents/locale/sl/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/sl/LC_MESSAGES/django.po +20 -0
- wagtail/documents/models.py +5 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
- wagtail/documents/tests/test_models.py +5 -1
- wagtail/embeds/apps.py +2 -0
- wagtail/embeds/embeds.py +12 -14
- wagtail/embeds/finders/__init__.py +2 -0
- wagtail/embeds/finders/facebook.py +17 -33
- wagtail/embeds/finders/instagram.py +19 -16
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/signal_handlers.py +13 -0
- wagtail/embeds/tests/test_embeds.py +7 -7
- wagtail/fields.py +58 -14
- wagtail/images/__init__.py +1 -1
- wagtail/images/locale/en/LC_MESSAGES/django.po +34 -34
- wagtail/images/locale/sl/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/sl/LC_MESSAGES/django.po +20 -0
- wagtail/images/models.py +2 -0
- wagtail/images/static/wagtailimages/js/image-chooser-modal.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/templates/wagtailimages/images/edit.html +4 -4
- wagtail/images/tests/test_admin_views.py +26 -2
- wagtail/images/views/chooser.py +6 -1
- wagtail/locale/en/LC_MESSAGES/django.po +84 -80
- wagtail/locales/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/locales/tests.py +16 -0
- wagtail/locales/wagtail_hooks.py +0 -9
- wagtail/migrations/0094_alter_page_locale.py +19 -0
- wagtail/models/__init__.py +11 -5
- wagtail/models/i18n.py +6 -1
- wagtail/project_template/requirements.txt +1 -1
- wagtail/search/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/signals.py +4 -0
- wagtail/sites/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/sites/tests.py +15 -0
- wagtail/sites/wagtail_hooks.py +0 -9
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +9 -9
- wagtail/snippets/permissions.py +5 -3
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
- wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/menu.html +1 -1
- wagtail/snippets/tests/test_snippets.py +78 -12
- wagtail/snippets/tests/test_viewset.py +22 -0
- wagtail/snippets/views/snippets.py +19 -14
- wagtail/snippets/wagtail_hooks.py +2 -10
- wagtail/templatetags/wagtailcore_tags.py +3 -0
- wagtail/test/dummy_external_storage.py +1 -1
- wagtail/test/i18n/migrations/0003_alter_clusterabletestmodel_locale_and_more.py +40 -0
- wagtail/test/routablepage/models.py +4 -0
- wagtail/test/snippets/migrations/0012_alter_translatablesnippet_locale.py +20 -0
- wagtail/test/testapp/migrations/0038_sociallink.py +52 -0
- wagtail/test/testapp/migrations/0039_alter_eventcategory_locale_and_more.py +45 -0
- wagtail/test/testapp/models.py +24 -0
- wagtail/test/testapp/views.py +1 -0
- wagtail/test/testapp/wagtail_hooks.py +9 -0
- wagtail/test/urls_multilang.py +6 -1
- wagtail/test/urls_multilang_non_root.py +11 -0
- wagtail/tests/streamfield_migrations/test_migrations.py +53 -12
- wagtail/tests/test_audit_log.py +72 -2
- wagtail/tests/test_blocks.py +103 -0
- wagtail/tests/test_signals.py +49 -2
- wagtail/tests/test_streamfield.py +153 -0
- wagtail/tests/test_utils.py +14 -0
- wagtail/tests/tests.py +5 -0
- wagtail/users/apps.py +1 -0
- wagtail/users/forms.py +7 -0
- wagtail/users/locale/en/LC_MESSAGES/django.po +55 -50
- wagtail/users/models.py +1 -0
- wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +3 -2
- wagtail/users/templatetags/wagtailusers_tags.py +9 -0
- wagtail/users/tests/__init__.py +7 -1
- wagtail/users/tests/test_admin_views.py +117 -32
- wagtail/users/views/groups.py +4 -0
- wagtail/users/views/users.py +58 -14
- wagtail/users/wagtail_hooks.py +7 -123
- wagtail/utils/utils.py +1 -0
- wagtail/utils/version.py +5 -2
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/METADATA +3 -3
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/RECORD +248 -222
- wagtail/admin/templates/wagtailadmin/reports/aging_pages.html +0 -58
- wagtail/admin/templates/wagtailadmin/reports/page_types_usage.html +0 -18
- wagtail/admin/templates/wagtailadmin/reports/site_history.html +0 -57
- wagtail/admin/templates/wagtailadmin/reports/workflow.html +0 -81
- wagtail/admin/templates/wagtailadmin/reports/workflow_tasks.html +0 -63
- wagtail/contrib/frontend_cache/backends.py +0 -400
- wagtail/contrib/redirects/templates/wagtailredirects/list.html +0 -43
- wagtail/contrib/redirects/templates/wagtailredirects/reports/redirects_report.html +0 -14
- wagtail/contrib/redirects/tests/test_reports_view.py +0 -82
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/LICENSE +0 -0
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/WHEEL +0 -0
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-6.1.3.dist-info → wagtail-6.2rc1.dist-info}/top_level.txt +0 -0
|
@@ -21,6 +21,7 @@ from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn
|
|
|
21
21
|
from wagtail.admin.utils import set_query_params
|
|
22
22
|
from wagtail.admin.views.account import BaseSettingsPanel
|
|
23
23
|
from wagtail.admin.widgets import Button
|
|
24
|
+
from wagtail.permission_policies.base import ModelPermissionPolicy
|
|
24
25
|
from wagtail.snippets.bulk_actions.snippet_bulk_action import SnippetBulkAction
|
|
25
26
|
from wagtail.snippets.models import register_snippet
|
|
26
27
|
from wagtail.snippets.views.chooser import SnippetChooserViewSet
|
|
@@ -264,6 +265,13 @@ class FullFeaturedSnippetFilterSet(WagtailFilterSet):
|
|
|
264
265
|
fields = ["country_code", "some_date"]
|
|
265
266
|
|
|
266
267
|
|
|
268
|
+
class FullFeaturedPermissionPolicy(ModelPermissionPolicy):
|
|
269
|
+
def user_has_permission(self, user, action):
|
|
270
|
+
if not user.is_anonymous and "[FORBIDDEN]" in user.get_full_name():
|
|
271
|
+
return False
|
|
272
|
+
return super().user_has_permission(user, action)
|
|
273
|
+
|
|
274
|
+
|
|
267
275
|
class FullFeaturedSnippetChooserViewSet(SnippetChooserViewSet):
|
|
268
276
|
form_fields = ["text", "country_code", "some_number"]
|
|
269
277
|
|
|
@@ -303,6 +311,7 @@ class FullFeaturedSnippetViewSet(SnippetViewSet):
|
|
|
303
311
|
# Ensure that the menu item is placed last
|
|
304
312
|
menu_order = 999999
|
|
305
313
|
inspect_view_enabled = True
|
|
314
|
+
permission_policy = FullFeaturedPermissionPolicy(FullFeaturedSnippet)
|
|
306
315
|
|
|
307
316
|
class IndexView(SnippetViewSet.index_view_class):
|
|
308
317
|
def get_add_url(self):
|
wagtail/test/urls_multilang.py
CHANGED
|
@@ -2,5 +2,10 @@ from django.conf.urls.i18n import i18n_patterns
|
|
|
2
2
|
from django.urls import include, path
|
|
3
3
|
|
|
4
4
|
from wagtail import urls as wagtail_urls
|
|
5
|
+
from wagtail.admin import urls as wagtailadmin_urls
|
|
5
6
|
|
|
6
|
-
urlpatterns =
|
|
7
|
+
urlpatterns = [
|
|
8
|
+
path("admin/", include(wagtailadmin_urls)),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
urlpatterns += i18n_patterns(path("", include(wagtail_urls)))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from django.conf.urls.i18n import i18n_patterns
|
|
2
|
+
from django.urls import include, path
|
|
3
|
+
|
|
4
|
+
from wagtail import urls as wagtail_urls
|
|
5
|
+
from wagtail.admin import urls as wagtailadmin_urls
|
|
6
|
+
|
|
7
|
+
urlpatterns = [
|
|
8
|
+
path("admin/", include(wagtailadmin_urls)),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
urlpatterns += i18n_patterns(path("site/", include(wagtail_urls)))
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
-
from django.db
|
|
4
|
+
from django.db import connection
|
|
5
|
+
from django.db.models import F, JSONField, TextField
|
|
5
6
|
from django.db.models.functions import Cast
|
|
6
7
|
from django.test import TestCase
|
|
7
8
|
from django.utils import timezone
|
|
@@ -24,8 +25,8 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
|
|
|
24
25
|
]
|
|
25
26
|
app_name = None
|
|
26
27
|
|
|
27
|
-
def
|
|
28
|
-
|
|
28
|
+
def _get_test_instances(self):
|
|
29
|
+
return [
|
|
29
30
|
self.factory(
|
|
30
31
|
content__0__char1="Test char 1",
|
|
31
32
|
content__1__char1="Test char 2",
|
|
@@ -44,6 +45,9 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
|
|
|
44
45
|
),
|
|
45
46
|
]
|
|
46
47
|
|
|
48
|
+
def setUp(self):
|
|
49
|
+
instances = self._get_test_instances()
|
|
50
|
+
|
|
47
51
|
self.original_raw_data = {}
|
|
48
52
|
self.original_revisions = {}
|
|
49
53
|
|
|
@@ -102,9 +106,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
|
|
|
102
106
|
|
|
103
107
|
self.apply_migration()
|
|
104
108
|
|
|
105
|
-
instances = self.model.objects.all()
|
|
106
|
-
raw_content=Cast(F("content"), JSONField())
|
|
107
|
-
)
|
|
109
|
+
instances = self.model.objects.all()
|
|
108
110
|
|
|
109
111
|
for instance in instances:
|
|
110
112
|
old_revisions = self.original_revisions[instance.id]
|
|
@@ -128,9 +130,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
|
|
|
128
130
|
revisions_from = timezone.now() + datetime.timedelta(days=2)
|
|
129
131
|
self.apply_migration(revisions_from=revisions_from)
|
|
130
132
|
|
|
131
|
-
instances = self.model.objects.all()
|
|
132
|
-
raw_content=Cast(F("content"), JSONField())
|
|
133
|
-
)
|
|
133
|
+
instances = self.model.objects.all()
|
|
134
134
|
|
|
135
135
|
for instance in instances:
|
|
136
136
|
old_revisions = self.original_revisions[instance.id]
|
|
@@ -159,9 +159,7 @@ class BaseMigrationTest(TestCase, MigrationTestMixin):
|
|
|
159
159
|
revisions_from = timezone.now() - datetime.timedelta(days=2)
|
|
160
160
|
self.apply_migration(revisions_from=revisions_from)
|
|
161
161
|
|
|
162
|
-
instances = self.model.objects.all()
|
|
163
|
-
raw_content=Cast(F("content"), JSONField())
|
|
164
|
-
)
|
|
162
|
+
instances = self.model.objects.all()
|
|
165
163
|
|
|
166
164
|
for instance in instances:
|
|
167
165
|
old_revisions = self.original_revisions[instance.id]
|
|
@@ -209,3 +207,46 @@ class TestPage(BaseMigrationTest):
|
|
|
209
207
|
|
|
210
208
|
def test_migrate_revisions_from_date(self):
|
|
211
209
|
self._test_migrate_revisions_from_date()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class TestNullStreamField(BaseMigrationTest):
|
|
213
|
+
"""
|
|
214
|
+
Migrations are processed if the underlying JSON is null.
|
|
215
|
+
|
|
216
|
+
This might occur if we're operating on a StreamField that was added to a model that
|
|
217
|
+
had existing records.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
model = models.SamplePage
|
|
221
|
+
factory = factories.SamplePageFactory
|
|
222
|
+
has_revisions = True
|
|
223
|
+
app_name = "streamfield_migration_tests"
|
|
224
|
+
|
|
225
|
+
def _get_test_instances(self):
|
|
226
|
+
return self.factory.create_batch(1, content=None)
|
|
227
|
+
|
|
228
|
+
def setUp(self):
|
|
229
|
+
super().setUp()
|
|
230
|
+
|
|
231
|
+
# Bypass StreamField/StreamBlock processing that cast a None stream field value
|
|
232
|
+
# to the empty StreamValue, and set the underlying JSON to null.
|
|
233
|
+
with connection.cursor() as cursor:
|
|
234
|
+
cursor.execute(f"UPDATE {self.model._meta.db_table} SET content = 'null'")
|
|
235
|
+
|
|
236
|
+
def assert_null_content(self):
|
|
237
|
+
"""
|
|
238
|
+
The raw JSON of all instances for this test is null.
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
instances = self.model.objects.all().annotate(
|
|
242
|
+
raw_content=Cast(F("content"), TextField())
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
for instance in instances:
|
|
246
|
+
with self.subTest(instance=instance):
|
|
247
|
+
self.assertEqual(instance.raw_content, "null")
|
|
248
|
+
|
|
249
|
+
def test_migrate_stream_data(self):
|
|
250
|
+
self.assert_null_content()
|
|
251
|
+
self.apply_migration()
|
|
252
|
+
self.assert_null_content()
|
wagtail/tests/test_audit_log.py
CHANGED
|
@@ -3,6 +3,7 @@ import json
|
|
|
3
3
|
|
|
4
4
|
from django.conf import settings
|
|
5
5
|
from django.contrib.auth import get_user_model
|
|
6
|
+
from django.contrib.contenttypes.models import ContentType
|
|
6
7
|
from django.core.exceptions import ValidationError
|
|
7
8
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
8
9
|
from django.test import TestCase
|
|
@@ -10,6 +11,7 @@ from django.utils import timezone
|
|
|
10
11
|
from freezegun import freeze_time
|
|
11
12
|
|
|
12
13
|
from wagtail.log_actions import LogActionRegistry
|
|
14
|
+
from wagtail.log_actions import registry as log_registry
|
|
13
15
|
from wagtail.models import (
|
|
14
16
|
Page,
|
|
15
17
|
PageLogEntry,
|
|
@@ -36,8 +38,13 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
|
|
|
36
38
|
title="Simple page", slug="simple", content="Hello", owner=self.user
|
|
37
39
|
)
|
|
38
40
|
)
|
|
41
|
+
self.snippet_1 = FullFeaturedSnippet.objects.create(text="snippet 1")
|
|
42
|
+
self.snippet_2 = FullFeaturedSnippet.objects.create(text="snippet 2")
|
|
43
|
+
self.snippet_content_type = ContentType.objects.get_for_model(
|
|
44
|
+
FullFeaturedSnippet
|
|
45
|
+
)
|
|
39
46
|
|
|
40
|
-
def
|
|
47
|
+
def test_log_action_for_page(self):
|
|
41
48
|
now = timezone.now()
|
|
42
49
|
|
|
43
50
|
with freeze_time(now):
|
|
@@ -49,7 +56,19 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
|
|
|
49
56
|
self.assertEqual(entry.user, self.user)
|
|
50
57
|
self.assertEqual(entry.timestamp, now)
|
|
51
58
|
|
|
52
|
-
def
|
|
59
|
+
def test_log_action_for_snippet(self):
|
|
60
|
+
now = timezone.now()
|
|
61
|
+
|
|
62
|
+
with freeze_time(now):
|
|
63
|
+
entry = ModelLogEntry.objects.log_action(
|
|
64
|
+
self.snippet_1, "wagtail.edit", user=self.user
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self.assertEqual(entry.content_type, self.snippet_content_type)
|
|
68
|
+
self.assertEqual(entry.user, self.user)
|
|
69
|
+
self.assertEqual(entry.timestamp, now)
|
|
70
|
+
|
|
71
|
+
def test_get_for_page_model(self):
|
|
53
72
|
PageLogEntry.objects.log_action(self.page, "wagtail.edit")
|
|
54
73
|
PageLogEntry.objects.log_action(self.simple_page, "wagtail.edit")
|
|
55
74
|
|
|
@@ -59,11 +78,62 @@ class TestAuditLogManager(WagtailTestUtils, TestCase):
|
|
|
59
78
|
list(entries), list(PageLogEntry.objects.filter(page=self.simple_page))
|
|
60
79
|
)
|
|
61
80
|
|
|
81
|
+
def test_get_for_snippet_model(self):
|
|
82
|
+
ModelLogEntry.objects.log_action(self.snippet_1, "wagtail.edit")
|
|
83
|
+
ModelLogEntry.objects.log_action(self.snippet_2, "wagtail.edit")
|
|
84
|
+
|
|
85
|
+
entries = ModelLogEntry.objects.get_for_model(FullFeaturedSnippet)
|
|
86
|
+
self.assertEqual(entries.count(), 2)
|
|
87
|
+
self.assertListEqual(
|
|
88
|
+
list(entries),
|
|
89
|
+
list(ModelLogEntry.objects.filter(content_type=self.snippet_content_type)),
|
|
90
|
+
)
|
|
91
|
+
|
|
62
92
|
def test_get_for_user(self):
|
|
63
93
|
self.assertEqual(
|
|
64
94
|
PageLogEntry.objects.get_for_user(self.user).count(), 1
|
|
65
95
|
) # the create from setUp
|
|
66
96
|
|
|
97
|
+
def test_get_for_page_instance(self):
|
|
98
|
+
PageLogEntry.objects.log_action(self.page, "wagtail.edit")
|
|
99
|
+
PageLogEntry.objects.log_action(self.simple_page, "wagtail.edit")
|
|
100
|
+
other_simple_page = self.page.add_child(
|
|
101
|
+
instance=SimplePage(
|
|
102
|
+
title="Simple page 2", slug="simple2", content="Hello", owner=self.user
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
PageLogEntry.objects.log_action(other_simple_page, "wagtail.edit")
|
|
106
|
+
|
|
107
|
+
entries = PageLogEntry.objects.for_instance(self.simple_page)
|
|
108
|
+
expected_entries = list(PageLogEntry.objects.filter(page=self.simple_page))
|
|
109
|
+
self.assertEqual(entries.count(), 2)
|
|
110
|
+
self.assertListEqual(list(entries), expected_entries)
|
|
111
|
+
|
|
112
|
+
# should also be able to retrieve entries via the log registry, which
|
|
113
|
+
# eliminates the need to know that PageLogEntry is the log entry model
|
|
114
|
+
entries = log_registry.get_logs_for_instance(self.simple_page)
|
|
115
|
+
self.assertEqual(entries.count(), 2)
|
|
116
|
+
self.assertListEqual(list(entries), expected_entries)
|
|
117
|
+
|
|
118
|
+
def test_get_for_snippet_instance(self):
|
|
119
|
+
ModelLogEntry.objects.log_action(self.snippet_1, "wagtail.edit")
|
|
120
|
+
ModelLogEntry.objects.log_action(self.snippet_2, "wagtail.edit")
|
|
121
|
+
|
|
122
|
+
entries = ModelLogEntry.objects.for_instance(self.snippet_1)
|
|
123
|
+
expected_entries = list(
|
|
124
|
+
ModelLogEntry.objects.filter(
|
|
125
|
+
content_type=self.snippet_content_type, object_id=self.snippet_1.pk
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
self.assertEqual(entries.count(), 1)
|
|
129
|
+
self.assertListEqual(list(entries), expected_entries)
|
|
130
|
+
|
|
131
|
+
# should also be able to retrieve entries via the log registry, which
|
|
132
|
+
# eliminates the need to know that ModelLogEntry is the log entry model
|
|
133
|
+
entries = log_registry.get_logs_for_instance(self.snippet_1)
|
|
134
|
+
self.assertEqual(entries.count(), 1)
|
|
135
|
+
self.assertListEqual(list(entries), expected_entries)
|
|
136
|
+
|
|
67
137
|
|
|
68
138
|
class TestAuditLog(TestCase):
|
|
69
139
|
def setUp(self):
|
wagtail/tests/test_blocks.py
CHANGED
|
@@ -17,6 +17,7 @@ from django.utils.translation import gettext_lazy as _
|
|
|
17
17
|
|
|
18
18
|
from wagtail import blocks
|
|
19
19
|
from wagtail.blocks.base import get_error_json_data
|
|
20
|
+
from wagtail.blocks.definition_lookup import BlockDefinitionLookup
|
|
20
21
|
from wagtail.blocks.field_block import FieldBlockAdapter
|
|
21
22
|
from wagtail.blocks.list_block import ListBlockAdapter, ListBlockValidationError
|
|
22
23
|
from wagtail.blocks.static_block import StaticBlockAdapter
|
|
@@ -5882,3 +5883,105 @@ class TestValidationErrorAsJsonData(TestCase):
|
|
|
5882
5883
|
],
|
|
5883
5884
|
},
|
|
5884
5885
|
)
|
|
5886
|
+
|
|
5887
|
+
|
|
5888
|
+
class TestBlockDefinitionLookup(TestCase):
|
|
5889
|
+
def test_simple_lookup(self):
|
|
5890
|
+
lookup = BlockDefinitionLookup(
|
|
5891
|
+
{
|
|
5892
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
5893
|
+
1: ("wagtail.blocks.RichTextBlock", [], {}),
|
|
5894
|
+
}
|
|
5895
|
+
)
|
|
5896
|
+
char_block = lookup.get_block(0)
|
|
5897
|
+
char_block.set_name("title")
|
|
5898
|
+
self.assertIsInstance(char_block, blocks.CharBlock)
|
|
5899
|
+
self.assertTrue(char_block.required)
|
|
5900
|
+
|
|
5901
|
+
rich_text_block = lookup.get_block(1)
|
|
5902
|
+
self.assertIsInstance(rich_text_block, blocks.RichTextBlock)
|
|
5903
|
+
|
|
5904
|
+
# A subsequent call to get_block with the same index should return a new instance;
|
|
5905
|
+
# this ensures that state changes such as set_name are independent of other blocks
|
|
5906
|
+
char_block_2 = lookup.get_block(0)
|
|
5907
|
+
char_block_2.set_name("subtitle")
|
|
5908
|
+
self.assertIsInstance(char_block, blocks.CharBlock)
|
|
5909
|
+
self.assertTrue(char_block.required)
|
|
5910
|
+
self.assertIsNot(char_block, char_block_2)
|
|
5911
|
+
self.assertEqual(char_block.name, "title")
|
|
5912
|
+
self.assertEqual(char_block_2.name, "subtitle")
|
|
5913
|
+
|
|
5914
|
+
def test_structblock_lookup(self):
|
|
5915
|
+
lookup = BlockDefinitionLookup(
|
|
5916
|
+
{
|
|
5917
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
5918
|
+
1: ("wagtail.blocks.RichTextBlock", [], {}),
|
|
5919
|
+
2: (
|
|
5920
|
+
"wagtail.blocks.StructBlock",
|
|
5921
|
+
[
|
|
5922
|
+
[
|
|
5923
|
+
("title", 0),
|
|
5924
|
+
("description", 1),
|
|
5925
|
+
],
|
|
5926
|
+
],
|
|
5927
|
+
{},
|
|
5928
|
+
),
|
|
5929
|
+
}
|
|
5930
|
+
)
|
|
5931
|
+
struct_block = lookup.get_block(2)
|
|
5932
|
+
self.assertIsInstance(struct_block, blocks.StructBlock)
|
|
5933
|
+
title_block = struct_block.child_blocks["title"]
|
|
5934
|
+
self.assertIsInstance(title_block, blocks.CharBlock)
|
|
5935
|
+
self.assertTrue(title_block.required)
|
|
5936
|
+
description_block = struct_block.child_blocks["description"]
|
|
5937
|
+
self.assertIsInstance(description_block, blocks.RichTextBlock)
|
|
5938
|
+
|
|
5939
|
+
def test_streamblock_lookup(self):
|
|
5940
|
+
lookup = BlockDefinitionLookup(
|
|
5941
|
+
{
|
|
5942
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
5943
|
+
1: ("wagtail.blocks.RichTextBlock", [], {}),
|
|
5944
|
+
2: (
|
|
5945
|
+
"wagtail.blocks.StreamBlock",
|
|
5946
|
+
[
|
|
5947
|
+
[
|
|
5948
|
+
("heading", 0),
|
|
5949
|
+
("paragraph", 1),
|
|
5950
|
+
],
|
|
5951
|
+
],
|
|
5952
|
+
{},
|
|
5953
|
+
),
|
|
5954
|
+
}
|
|
5955
|
+
)
|
|
5956
|
+
stream_block = lookup.get_block(2)
|
|
5957
|
+
self.assertIsInstance(stream_block, blocks.StreamBlock)
|
|
5958
|
+
title_block = stream_block.child_blocks["heading"]
|
|
5959
|
+
self.assertIsInstance(title_block, blocks.CharBlock)
|
|
5960
|
+
self.assertTrue(title_block.required)
|
|
5961
|
+
description_block = stream_block.child_blocks["paragraph"]
|
|
5962
|
+
self.assertIsInstance(description_block, blocks.RichTextBlock)
|
|
5963
|
+
|
|
5964
|
+
def test_listblock_lookup(self):
|
|
5965
|
+
lookup = BlockDefinitionLookup(
|
|
5966
|
+
{
|
|
5967
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
5968
|
+
1: ("wagtail.blocks.ListBlock", [0], {}),
|
|
5969
|
+
}
|
|
5970
|
+
)
|
|
5971
|
+
list_block = lookup.get_block(1)
|
|
5972
|
+
self.assertIsInstance(list_block, blocks.ListBlock)
|
|
5973
|
+
list_item_block = list_block.child_block
|
|
5974
|
+
self.assertIsInstance(list_item_block, blocks.CharBlock)
|
|
5975
|
+
self.assertTrue(list_item_block.required)
|
|
5976
|
+
|
|
5977
|
+
# Passing a class as the child block is still valid; this is not converted
|
|
5978
|
+
# to a reference
|
|
5979
|
+
lookup = BlockDefinitionLookup(
|
|
5980
|
+
{
|
|
5981
|
+
0: ("wagtail.blocks.ListBlock", [blocks.CharBlock], {}),
|
|
5982
|
+
}
|
|
5983
|
+
)
|
|
5984
|
+
list_block = lookup.get_block(0)
|
|
5985
|
+
self.assertIsInstance(list_block, blocks.ListBlock)
|
|
5986
|
+
list_item_block = list_block.child_block
|
|
5987
|
+
self.assertIsInstance(list_item_block, blocks.CharBlock)
|
wagtail/tests/test_signals.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from unittest import mock
|
|
2
2
|
|
|
3
|
+
from django.conf import settings
|
|
3
4
|
from django.test import TestCase
|
|
4
5
|
|
|
5
|
-
from wagtail.models import Site
|
|
6
|
-
from wagtail.signals import page_slug_changed
|
|
6
|
+
from wagtail.models import Locale, Site
|
|
7
|
+
from wagtail.signals import copy_for_translation_done, page_slug_changed
|
|
7
8
|
from wagtail.test.testapp.models import SimplePage
|
|
8
9
|
from wagtail.test.utils import WagtailTestUtils
|
|
9
10
|
|
|
@@ -97,3 +98,49 @@ class TestPageSlugChangedSignal(WagtailTestUtils, TestCase):
|
|
|
97
98
|
|
|
98
99
|
# Check the signal was NOT fired
|
|
99
100
|
self.assertEqual(handler.call_count, 0)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class TestCopyForTranslationDoneSignal(WagtailTestUtils, TestCase):
|
|
104
|
+
"""
|
|
105
|
+
Tests for the `wagtail.signals.copy_for_translation_done` signal
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def setUp(self):
|
|
109
|
+
# Find root page
|
|
110
|
+
site = Site.objects.select_related("root_page").get(is_default_site=True)
|
|
111
|
+
root_page = site.root_page
|
|
112
|
+
|
|
113
|
+
# Create a subpage
|
|
114
|
+
self.subpage = SimplePage(
|
|
115
|
+
title="Subpage in english", slug="subpage-in-english", content="hello"
|
|
116
|
+
)
|
|
117
|
+
root_page.add_child(instance=self.subpage)
|
|
118
|
+
|
|
119
|
+
# Get the languages and create locales
|
|
120
|
+
language_codes = dict(settings.LANGUAGES).keys()
|
|
121
|
+
|
|
122
|
+
for language_code in language_codes:
|
|
123
|
+
Locale.objects.get_or_create(language_code=language_code)
|
|
124
|
+
|
|
125
|
+
# Get the locales needed
|
|
126
|
+
self.locale = Locale.objects.get(language_code="en")
|
|
127
|
+
self.another_locale = Locale.objects.get(language_code="fr")
|
|
128
|
+
|
|
129
|
+
root_page.copy_for_translation(self.another_locale)
|
|
130
|
+
|
|
131
|
+
def test_signal_emitted_on_copy_for_translation_done(self):
|
|
132
|
+
# Connect a mock signal handler to the signal
|
|
133
|
+
handler = mock.MagicMock()
|
|
134
|
+
copy_for_translation_done.connect(handler)
|
|
135
|
+
|
|
136
|
+
page_to_translate = SimplePage.objects.get(id=self.subpage.id)
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
with self.captureOnCommitCallbacks(execute=True):
|
|
140
|
+
page_to_translate.copy_for_translation(self.another_locale)
|
|
141
|
+
finally:
|
|
142
|
+
# Disconnect mock handler to prevent cross-test pollution
|
|
143
|
+
copy_for_translation_done.disconnect(handler)
|
|
144
|
+
|
|
145
|
+
# Check the signal was fired
|
|
146
|
+
self.assertEqual(handler.call_count, 1)
|
|
@@ -721,3 +721,156 @@ class TestGetBlockByContentPath(TestCase):
|
|
|
721
721
|
self.assertEqual(bound_block.value, "Barnaby Rudge")
|
|
722
722
|
bound_block = field.get_block_by_content_path(self.page.body, ["456", "999"])
|
|
723
723
|
self.assertIsNone(bound_block)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
class TestConstructStreamFieldFromLookup(TestCase):
|
|
727
|
+
def test_construct_block_list_from_lookup(self):
|
|
728
|
+
field = StreamField(
|
|
729
|
+
[
|
|
730
|
+
("heading", 0),
|
|
731
|
+
("paragraph", 1),
|
|
732
|
+
("button", 3),
|
|
733
|
+
],
|
|
734
|
+
block_lookup={
|
|
735
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
736
|
+
1: ("wagtail.blocks.RichTextBlock", [], {}),
|
|
737
|
+
2: ("wagtail.blocks.PageChooserBlock", [], {}),
|
|
738
|
+
3: (
|
|
739
|
+
"wagtail.blocks.StructBlock",
|
|
740
|
+
[
|
|
741
|
+
[
|
|
742
|
+
("page", 2),
|
|
743
|
+
("link_text", 0),
|
|
744
|
+
]
|
|
745
|
+
],
|
|
746
|
+
{},
|
|
747
|
+
),
|
|
748
|
+
},
|
|
749
|
+
)
|
|
750
|
+
stream_block = field.stream_block
|
|
751
|
+
self.assertIsInstance(stream_block, blocks.StreamBlock)
|
|
752
|
+
self.assertEqual(len(stream_block.child_blocks), 3)
|
|
753
|
+
|
|
754
|
+
heading_block = stream_block.child_blocks["heading"]
|
|
755
|
+
self.assertIsInstance(heading_block, blocks.CharBlock)
|
|
756
|
+
self.assertTrue(heading_block.required)
|
|
757
|
+
self.assertEqual(heading_block.name, "heading")
|
|
758
|
+
|
|
759
|
+
paragraph_block = stream_block.child_blocks["paragraph"]
|
|
760
|
+
self.assertIsInstance(paragraph_block, blocks.RichTextBlock)
|
|
761
|
+
self.assertEqual(paragraph_block.name, "paragraph")
|
|
762
|
+
|
|
763
|
+
button_block = stream_block.child_blocks["button"]
|
|
764
|
+
self.assertIsInstance(button_block, blocks.StructBlock)
|
|
765
|
+
self.assertEqual(button_block.name, "button")
|
|
766
|
+
self.assertEqual(len(button_block.child_blocks), 2)
|
|
767
|
+
page_block = button_block.child_blocks["page"]
|
|
768
|
+
self.assertIsInstance(page_block, blocks.PageChooserBlock)
|
|
769
|
+
link_text_block = button_block.child_blocks["link_text"]
|
|
770
|
+
self.assertIsInstance(link_text_block, blocks.CharBlock)
|
|
771
|
+
self.assertEqual(link_text_block.name, "link_text")
|
|
772
|
+
|
|
773
|
+
def test_construct_top_level_block_from_lookup(self):
|
|
774
|
+
field = StreamField(
|
|
775
|
+
4,
|
|
776
|
+
block_lookup={
|
|
777
|
+
0: ("wagtail.blocks.CharBlock", [], {"required": True}),
|
|
778
|
+
1: ("wagtail.blocks.RichTextBlock", [], {}),
|
|
779
|
+
2: ("wagtail.blocks.PageChooserBlock", [], {}),
|
|
780
|
+
3: (
|
|
781
|
+
"wagtail.blocks.StructBlock",
|
|
782
|
+
[
|
|
783
|
+
[
|
|
784
|
+
("page", 2),
|
|
785
|
+
("link_text", 0),
|
|
786
|
+
]
|
|
787
|
+
],
|
|
788
|
+
{},
|
|
789
|
+
),
|
|
790
|
+
4: (
|
|
791
|
+
"wagtail.blocks.StreamBlock",
|
|
792
|
+
[
|
|
793
|
+
[
|
|
794
|
+
("heading", 0),
|
|
795
|
+
("paragraph", 1),
|
|
796
|
+
("button", 3),
|
|
797
|
+
]
|
|
798
|
+
],
|
|
799
|
+
{},
|
|
800
|
+
),
|
|
801
|
+
},
|
|
802
|
+
)
|
|
803
|
+
stream_block = field.stream_block
|
|
804
|
+
self.assertIsInstance(stream_block, blocks.StreamBlock)
|
|
805
|
+
self.assertEqual(len(stream_block.child_blocks), 3)
|
|
806
|
+
|
|
807
|
+
heading_block = stream_block.child_blocks["heading"]
|
|
808
|
+
self.assertIsInstance(heading_block, blocks.CharBlock)
|
|
809
|
+
self.assertTrue(heading_block.required)
|
|
810
|
+
self.assertEqual(heading_block.name, "heading")
|
|
811
|
+
|
|
812
|
+
paragraph_block = stream_block.child_blocks["paragraph"]
|
|
813
|
+
self.assertIsInstance(paragraph_block, blocks.RichTextBlock)
|
|
814
|
+
self.assertEqual(paragraph_block.name, "paragraph")
|
|
815
|
+
|
|
816
|
+
button_block = stream_block.child_blocks["button"]
|
|
817
|
+
self.assertIsInstance(button_block, blocks.StructBlock)
|
|
818
|
+
self.assertEqual(button_block.name, "button")
|
|
819
|
+
self.assertEqual(len(button_block.child_blocks), 2)
|
|
820
|
+
page_block = button_block.child_blocks["page"]
|
|
821
|
+
self.assertIsInstance(page_block, blocks.PageChooserBlock)
|
|
822
|
+
link_text_block = button_block.child_blocks["link_text"]
|
|
823
|
+
self.assertIsInstance(link_text_block, blocks.CharBlock)
|
|
824
|
+
self.assertEqual(link_text_block.name, "link_text")
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
class TestDeconstructStreamFieldWithLookup(TestCase):
|
|
828
|
+
def test_deconstruct(self):
|
|
829
|
+
class ButtonBlock(blocks.StructBlock):
|
|
830
|
+
page = blocks.PageChooserBlock()
|
|
831
|
+
link_text = blocks.CharBlock(required=True)
|
|
832
|
+
|
|
833
|
+
field = StreamField(
|
|
834
|
+
[
|
|
835
|
+
("heading", blocks.CharBlock(required=True)),
|
|
836
|
+
("paragraph", blocks.RichTextBlock()),
|
|
837
|
+
("button", ButtonBlock()),
|
|
838
|
+
],
|
|
839
|
+
blank=True,
|
|
840
|
+
)
|
|
841
|
+
field.set_attributes_from_name("body")
|
|
842
|
+
|
|
843
|
+
name, path, args, kwargs = field.deconstruct()
|
|
844
|
+
self.assertEqual(name, "body")
|
|
845
|
+
self.assertEqual(path, "wagtail.fields.StreamField")
|
|
846
|
+
self.assertEqual(
|
|
847
|
+
args,
|
|
848
|
+
[
|
|
849
|
+
[
|
|
850
|
+
("heading", 0),
|
|
851
|
+
("paragraph", 1),
|
|
852
|
+
("button", 3),
|
|
853
|
+
]
|
|
854
|
+
],
|
|
855
|
+
)
|
|
856
|
+
self.assertEqual(
|
|
857
|
+
kwargs,
|
|
858
|
+
{
|
|
859
|
+
"blank": True,
|
|
860
|
+
"block_lookup": {
|
|
861
|
+
0: ("wagtail.blocks.CharBlock", (), {"required": True}),
|
|
862
|
+
1: ("wagtail.blocks.RichTextBlock", (), {}),
|
|
863
|
+
2: ("wagtail.blocks.PageChooserBlock", (), {}),
|
|
864
|
+
3: (
|
|
865
|
+
"wagtail.blocks.StructBlock",
|
|
866
|
+
[
|
|
867
|
+
[
|
|
868
|
+
("page", 2),
|
|
869
|
+
("link_text", 0),
|
|
870
|
+
]
|
|
871
|
+
],
|
|
872
|
+
{},
|
|
873
|
+
),
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
)
|
wagtail/tests/test_utils.py
CHANGED
|
@@ -29,6 +29,7 @@ from wagtail.coreutils import (
|
|
|
29
29
|
from wagtail.models import Page, Site
|
|
30
30
|
from wagtail.utils.file import hash_filelike
|
|
31
31
|
from wagtail.utils.utils import deep_update, flatten_choices
|
|
32
|
+
from wagtail.utils.version import get_main_version
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class TestCamelCaseToUnderscore(TestCase):
|
|
@@ -577,6 +578,19 @@ class HashFileLikeTestCase(SimpleTestCase):
|
|
|
577
578
|
)
|
|
578
579
|
|
|
579
580
|
|
|
581
|
+
class TestVersion(SimpleTestCase):
|
|
582
|
+
def test_get_main_version(self):
|
|
583
|
+
cases = [
|
|
584
|
+
((6, 2, 0, "final", 0), False, "6.2"),
|
|
585
|
+
((6, 2, 1, "final", 0), False, "6.2"),
|
|
586
|
+
((6, 2, 0, "final", 0), True, "6.2"),
|
|
587
|
+
((6, 2, 1, "final", 0), True, "6.2.1"),
|
|
588
|
+
]
|
|
589
|
+
for version, include_patch, expected in cases:
|
|
590
|
+
with self.subTest(version=version, include_patch=include_patch):
|
|
591
|
+
self.assertEqual(get_main_version(version, include_patch), expected)
|
|
592
|
+
|
|
593
|
+
|
|
580
594
|
class TestFlattenChoices(SimpleTestCase):
|
|
581
595
|
def test_tuple_choices(self):
|
|
582
596
|
choices = [(1, "1st"), (2, "2nd")]
|
wagtail/tests/tests.py
CHANGED
|
@@ -9,6 +9,7 @@ from django.test import TestCase
|
|
|
9
9
|
from django.test.utils import override_settings
|
|
10
10
|
from django.urls.exceptions import NoReverseMatch
|
|
11
11
|
from django.utils.safestring import SafeString
|
|
12
|
+
from django.utils.translation import gettext_lazy
|
|
12
13
|
|
|
13
14
|
from wagtail.coreutils import (
|
|
14
15
|
get_dummy_request,
|
|
@@ -536,6 +537,10 @@ class TestRichtextTag(TestCase):
|
|
|
536
537
|
self.assertEqual(result, "Hello world!")
|
|
537
538
|
self.assertIsInstance(result, SafeString)
|
|
538
539
|
|
|
540
|
+
def test_call_with_lazy(self):
|
|
541
|
+
result = richtext(gettext_lazy("test"))
|
|
542
|
+
self.assertEqual(result, "test")
|
|
543
|
+
|
|
539
544
|
def test_call_with_none(self):
|
|
540
545
|
result = richtext(None)
|
|
541
546
|
self.assertEqual(result, "")
|
wagtail/users/apps.py
CHANGED