wagtail 6.0.2__py3-none-any.whl → 6.1rc1__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/admin/checks.py +51 -0
- wagtail/admin/compare.py +1 -1
- wagtail/admin/filters.py +70 -1
- wagtail/admin/forms/account.py +1 -1
- wagtail/admin/forms/collections.py +15 -0
- wagtail/admin/forms/pages.py +49 -0
- wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/de/LC_MESSAGES/django.po +5 -5
- wagtail/admin/locale/en/LC_MESSAGES/django.po +474 -385
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +3 -3
- wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +73 -2
- wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ro/LC_MESSAGES/django.po +3 -3
- wagtail/admin/panels/comment_panel.py +1 -1
- wagtail/admin/panels/field_panel.py +1 -1
- wagtail/admin/rich_text/converters/editor_html.py +3 -1
- wagtail/admin/rich_text/editors/draftail/__init__.py +28 -2
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/css/panels/draftail.css +1 -1
- wagtail/admin/static/wagtailadmin/images/favicon.ico +0 -0
- 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/core.js.LICENSE.txt +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 +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/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/telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +4 -4
- wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
- wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
- wagtail/admin/staticfiles.py +1 -0
- wagtail/admin/templates/wagtailadmin/base.html +1 -0
- wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +3 -1
- wagtail/admin/templates/wagtailadmin/collections/index_results.html +10 -0
- wagtail/admin/templates/wagtailadmin/generic/base.html +1 -9
- wagtail/admin/templates/wagtailadmin/generic/form.html +3 -2
- wagtail/admin/templates/wagtailadmin/generic/history/action_cell.html +27 -0
- wagtail/admin/templates/wagtailadmin/home/workflow_objects_to_moderate.html +3 -3
- wagtail/admin/templates/wagtailadmin/icons/keyboard.svg +1 -0
- wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +3 -1
- wagtail/admin/templates/wagtailadmin/pages/_editor_js.html +0 -14
- wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html +3 -1
- wagtail/admin/templates/wagtailadmin/pages/choose_parent.html +17 -0
- wagtail/admin/templates/wagtailadmin/pages/explorable_index.html +8 -0
- wagtail/admin/templates/wagtailadmin/pages/history.html +1 -61
- wagtail/admin/templates/wagtailadmin/pages/index.html +1 -3
- wagtail/admin/templates/wagtailadmin/pages/listing/_locked_indicator.html +2 -2
- wagtail/admin/templates/wagtailadmin/pages/listing/_page_title_column_header.html +25 -27
- wagtail/admin/templates/wagtailadmin/pages/page_listing_header.html +2 -1
- wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
- wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html +3 -1
- wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/active_filters.html +2 -1
- wagtail/admin/templates/wagtailadmin/shared/breadcrumbs.html +8 -0
- wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/headers/page_edit_header.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/headers/slim_header.html +21 -9
- wagtail/admin/templates/wagtailadmin/shared/human_readable_date.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +29 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html +2 -1
- wagtail/admin/templates/wagtailadmin/skeleton.html +2 -1
- wagtail/admin/templates/wagtailadmin/tables/related_objects_cell.html +9 -0
- wagtail/admin/templates/wagtailadmin/tables/title_cell.html +9 -7
- wagtail/admin/templates/wagtailadmin/widgets/draftail_rich_text_area.html +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/create.html +6 -23
- wagtail/admin/templates/wagtailadmin/workflows/create_task.html +6 -15
- wagtail/admin/templates/wagtailadmin/workflows/edit.html +6 -23
- wagtail/admin/templates/wagtailadmin/workflows/edit_task.html +6 -13
- wagtail/admin/templates/wagtailadmin/workflows/includes/task_usage_cell.html +4 -4
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_tasks_cell.html +18 -0
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_title_cell.html +7 -0
- wagtail/admin/templates/wagtailadmin/workflows/includes/workflow_used_by_cell.html +25 -0
- wagtail/admin/templates/wagtailadmin/workflows/index.html +0 -99
- wagtail/admin/templates/wagtailadmin/workflows/index_results.html +10 -0
- wagtail/admin/templates/wagtailadmin/workflows/task_index.html +0 -30
- wagtail/admin/templates/wagtailadmin/workflows/task_index_results.html +10 -0
- wagtail/admin/templates/wagtailadmin/workflows/usage.html +1 -1
- wagtail/admin/templatetags/wagtailadmin_tags.py +116 -39
- wagtail/admin/tests/pages/test_create_page.py +10 -4
- wagtail/admin/tests/pages/test_custom_listing.py +37 -0
- wagtail/admin/tests/pages/test_edit_page.py +6 -6
- wagtail/admin/tests/pages/test_explorer_view.py +19 -18
- wagtail/admin/tests/pages/test_move_page.py +1 -1
- wagtail/admin/tests/pages/test_page_usage.py +50 -2
- wagtail/admin/tests/pages/test_parent_page_chooser_view.py +119 -0
- wagtail/admin/tests/pages/test_preview.py +18 -4
- wagtail/admin/tests/test_account_management.py +20 -1
- wagtail/admin/tests/test_audit_log.py +172 -5
- wagtail/admin/tests/test_checks.py +92 -0
- wagtail/admin/tests/test_collections_views.py +19 -5
- wagtail/admin/tests/test_compare.py +6 -6
- wagtail/admin/tests/test_dashboard.py +404 -0
- wagtail/admin/tests/test_dbwhitelister.py +4 -5
- wagtail/admin/tests/test_edit_handlers.py +2 -2
- wagtail/admin/tests/test_keyboard_shortcuts.py +84 -0
- wagtail/admin/tests/test_page_chooser.py +31 -18
- wagtail/admin/tests/test_privacy.py +36 -2
- wagtail/admin/tests/test_rich_text.py +168 -23
- wagtail/admin/tests/test_templatetags.py +411 -43
- wagtail/admin/tests/test_views.py +4 -2
- wagtail/admin/tests/test_workflows.py +531 -9
- wagtail/admin/tests/tests.py +3 -1
- wagtail/admin/tests/ui/test_tables.py +48 -1
- wagtail/admin/tests/viewsets/test_model_viewset.py +126 -29
- wagtail/admin/ui/side_panels.py +3 -1
- wagtail/admin/ui/tables/__init__.py +13 -1
- wagtail/admin/ui/tables/pages.py +17 -6
- wagtail/admin/urls/__init__.py +8 -3
- wagtail/admin/urls/pages.py +5 -0
- wagtail/admin/urls/workflows.py +10 -0
- wagtail/admin/views/chooser.py +20 -24
- wagtail/admin/views/collections.py +17 -1
- wagtail/admin/views/generic/base.py +31 -4
- wagtail/admin/views/generic/history.py +220 -51
- wagtail/admin/views/generic/mixins.py +7 -4
- wagtail/admin/views/generic/models.py +54 -38
- wagtail/admin/views/generic/multiple_upload.py +17 -8
- wagtail/admin/views/generic/usage.py +17 -11
- wagtail/admin/views/home.py +15 -12
- wagtail/admin/views/mixins.py +30 -0
- wagtail/admin/views/pages/choose_parent.py +73 -0
- wagtail/admin/views/pages/history.py +54 -66
- wagtail/admin/views/pages/listing.py +187 -106
- wagtail/admin/views/pages/usage.py +6 -1
- wagtail/admin/views/pages/utils.py +70 -1
- wagtail/admin/views/workflows.py +150 -21
- wagtail/admin/viewsets/model.py +2 -2
- wagtail/admin/viewsets/pages.py +77 -0
- wagtail/admin/wagtail_hooks.py +40 -2
- wagtail/admin/widgets/button.py +10 -9
- wagtail/api/v2/filters.py +1 -1
- wagtail/api/v2/tests/test_pages.py +1 -1
- wagtail/blocks/base.py +18 -9
- wagtail/blocks/field_block.py +9 -7
- wagtail/blocks/list_block.py +16 -6
- wagtail/blocks/static_block.py +3 -0
- wagtail/blocks/stream_block.py +58 -23
- wagtail/blocks/struct_block.py +15 -9
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +39 -47
- wagtail/contrib/forms/models.py +5 -5
- wagtail/contrib/forms/templates/wagtailforms/list_submissions.html +44 -33
- wagtail/contrib/forms/templates/wagtailforms/submissions_index.html +2 -63
- wagtail/contrib/forms/tests/test_models.py +26 -0
- wagtail/contrib/forms/urls.py +6 -0
- wagtail/contrib/forms/views.py +52 -49
- wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +34 -42
- wagtail/contrib/redirects/signal_handlers.py +1 -1
- wagtail/contrib/redirects/templates/wagtailredirects/index.html +1 -36
- wagtail/contrib/redirects/templates/wagtailredirects/index_results.html +18 -0
- wagtail/contrib/redirects/templates/wagtailredirects/redirect_target_cell.html +8 -0
- wagtail/contrib/redirects/tests/test_import_command.py +1 -1
- wagtail/contrib/redirects/tests/test_redirects.py +79 -8
- wagtail/contrib/redirects/urls.py +2 -1
- wagtail/contrib/redirects/views.py +85 -55
- wagtail/contrib/search_promotions/admin_urls.py +2 -1
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +41 -64
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index.html +1 -16
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/index_results.html +11 -0
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/list.html +0 -51
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/results.html +3 -16
- wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/search_promotion_column.html +15 -0
- wagtail/contrib/search_promotions/tests.py +122 -9
- wagtail/contrib/search_promotions/views.py +66 -65
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/settings/registry.py +10 -5
- wagtail/contrib/settings/tests/generic/test_admin.py +9 -0
- wagtail/contrib/settings/tests/site_specific/test_admin.py +10 -1
- wagtail/contrib/settings/tests/site_specific/test_model.py +3 -3
- wagtail/contrib/settings/tests/site_specific/test_templates.py +1 -1
- wagtail/contrib/settings/views.py +3 -1
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/simple_translation/tests/test_wagtail_hooks.py +2 -2
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +7 -7
- wagtail/contrib/table_block/blocks.py +1 -1
- 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/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
- wagtail/coreutils.py +3 -2
- wagtail/documents/admin_urls.py +2 -2
- wagtail/documents/locale/en/LC_MESSAGES/django.po +22 -22
- wagtail/documents/migrations/0013_delete_uploadeddocument.py +16 -0
- wagtail/documents/models.py +1 -20
- wagtail/documents/rich_text/__init__.py +11 -7
- 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/templates/wagtaildocs/documents/index.html +0 -16
- wagtail/documents/tests/test_admin_views.py +155 -23
- wagtail/documents/tests/test_collection_privacy.py +55 -1
- wagtail/documents/tests/test_rich_text.py +14 -0
- wagtail/documents/views/documents.py +25 -22
- wagtail/documents/views/multiple.py +6 -7
- wagtail/documents/views/serve.py +16 -1
- wagtail/documents/wagtail_hooks.py +20 -15
- wagtail/embeds/blocks.py +5 -0
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/embeds/rich_text/__init__.py +1 -1
- wagtail/embeds/tests/test_rich_text.py +14 -0
- wagtail/embeds/wagtail_hooks.py +4 -14
- wagtail/fields.py +3 -48
- wagtail/images/admin_urls.py +2 -2
- wagtail/images/check_files/wagtail.jpg +0 -0
- wagtail/images/check_files/wagtail.png +0 -0
- wagtail/images/fields.py +2 -0
- wagtail/images/image_operations.py +1 -1
- wagtail/images/locale/en/LC_MESSAGES/django.po +33 -45
- wagtail/images/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +4 -0
- wagtail/images/migrations/0026_delete_uploadedimage.py +16 -0
- wagtail/images/models.py +49 -43
- wagtail/images/rich_text/__init__.py +18 -8
- 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/image_listing_header.html +6 -0
- wagtail/images/templates/wagtailimages/images/index.html +11 -51
- wagtail/images/tests/test_admin_views.py +119 -62
- wagtail/images/tests/test_image_operations.py +10 -0
- wagtail/images/tests/test_models.py +35 -33
- wagtail/images/tests/test_rich_text.py +14 -0
- wagtail/images/tests/utils.py +1 -1
- wagtail/images/views/images.py +35 -64
- wagtail/images/views/multiple.py +6 -7
- wagtail/images/wagtail_hooks.py +4 -14
- wagtail/locale/en/LC_MESSAGES/django.po +150 -136
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/locales/tests.py +18 -3
- wagtail/locales/views.py +0 -1
- wagtail/management/commands/rebuild_references_index.py +3 -1
- wagtail/migrations/0092_alter_collectionviewrestriction_password_and_more.py +33 -0
- wagtail/migrations/0093_uploadedfile.py +53 -0
- wagtail/models/__init__.py +147 -32
- wagtail/models/i18n.py +1 -1
- wagtail/models/{collections.py → media.py} +33 -2
- wagtail/models/reference_index.py +1 -1
- wagtail/models/view_restrictions.py +10 -3
- wagtail/project_template/project_name/settings/base.py +6 -0
- wagtail/project_template/requirements.txt +1 -1
- wagtail/rich_text/__init__.py +25 -8
- wagtail/rich_text/pages.py +19 -8
- wagtail/rich_text/rewriters.py +140 -68
- wagtail/search/backends/database/mysql/mysql.py +3 -3
- wagtail/search/backends/database/postgres/postgres.py +3 -3
- wagtail/search/backends/database/sqlite/sqlite.py +2 -2
- wagtail/search/backends/elasticsearch7.py +4 -0
- wagtail/search/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/search/tests/test_postgres_backend.py +50 -0
- wagtail/sites/locale/en/LC_MESSAGES/django.po +8 -8
- wagtail/sites/tests.py +35 -9
- wagtail/sites/views.py +3 -1
- wagtail/snippets/locale/de/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/de/LC_MESSAGES/django.po +5 -6
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +16 -56
- 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/publish.html +3 -1
- wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html +3 -1
- wagtail/snippets/templates/wagtailsnippets/snippets/create.html +1 -1
- wagtail/snippets/templates/wagtailsnippets/snippets/edit.html +1 -1
- wagtail/snippets/tests/test_preview.py +13 -2
- wagtail/snippets/tests/test_snippets.py +41 -16
- wagtail/snippets/tests/test_viewset.py +63 -18
- wagtail/snippets/tests/test_workflows.py +12 -0
- wagtail/snippets/views/snippets.py +1 -40
- wagtail/templatetags/wagtailcore_tags.py +1 -1
- wagtail/test/demosite/models.py +1 -1
- wagtail/test/middleware.py +14 -1
- wagtail/test/testapp/fixtures/test.json +20 -0
- wagtail/test/testapp/migrations/0001_squashed_0073_revisablechildmodel_secret_text.py +8 -8
- wagtail/test/testapp/migrations/0023_snippetchoosermodel_full_featured.py +1 -0
- wagtail/test/testapp/migrations/0034_custompermissionmodel.py +44 -0
- wagtail/test/testapp/migrations/0035_modelwithcustommanager.py +30 -0
- wagtail/test/testapp/migrations/0036_complexdefaultstreampage.py +28 -0
- wagtail/test/testapp/models.py +79 -2
- wagtail/test/testapp/templates/tests/custom_docs_password_required.html +10 -0
- wagtail/test/testapp/templates/tests/custom_page_password_required.html +10 -0
- wagtail/test/testapp/views.py +24 -2
- wagtail/test/testapp/wagtail_hooks.py +19 -0
- wagtail/test/utils/wagtail_tests.py +2 -2
- wagtail/tests/test_blocks.py +262 -1
- wagtail/tests/test_migrations.py +1 -1
- wagtail/tests/test_page_model.py +77 -0
- wagtail/tests/test_page_privacy.py +18 -1
- wagtail/tests/test_rich_text.py +95 -5
- wagtail/tests/test_streamfield.py +43 -0
- wagtail/tests/test_utils.py +8 -2
- wagtail/tests/test_views.py +52 -1
- wagtail/tests/test_whitelist.py +7 -7
- wagtail/users/forms.py +3 -1
- wagtail/users/locale/en/LC_MESSAGES/django.po +124 -96
- wagtail/users/migrations/0013_userprofile_density.py +23 -0
- wagtail/users/models.py +14 -3
- wagtail/users/templates/wagtailusers/groups/create.html +1 -7
- wagtail/users/templates/wagtailusers/groups/edit.html +1 -13
- wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html +46 -2
- wagtail/users/templates/wagtailusers/groups/includes/group_form_js.html +0 -2
- wagtail/users/templates/wagtailusers/users/create.html +1 -9
- wagtail/users/templates/wagtailusers/users/edit.html +1 -9
- wagtail/users/templates/wagtailusers/users/index.html +2 -5
- wagtail/users/templates/wagtailusers/users/index_results.html +3 -13
- wagtail/users/templates/wagtailusers/users/user_cell.html +9 -0
- wagtail/users/templatetags/wagtailusers_tags.py +107 -20
- wagtail/users/tests/test_admin_views.py +669 -90
- wagtail/users/views/groups.py +58 -61
- wagtail/users/views/users.py +211 -92
- wagtail/users/wagtail_hooks.py +6 -38
- wagtail/users/widgets.py +3 -5
- wagtail/utils/text.py +1 -1
- wagtail/views.py +5 -9
- wagtail/whitelist.py +1 -1
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/METADATA +4 -5
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/RECORD +339 -320
- wagtail/admin/static/wagtailadmin/js/page-editor.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/mousetrap.min.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/urlify.js +0 -1
- wagtail/admin/static/wagtailadmin/js/vendor/xregexp.min.js +0 -1
- wagtail/admin/templates/wagtailadmin/collections/index.html +0 -34
- wagtail/admin/templates/wagtailadmin/pages/revisions/_actions.html +0 -22
- wagtail/admin/templates/wagtailadmin/shared/page_breadcrumbs.html +0 -55
- wagtail/admin/tests/pages/test_dashboard.py +0 -172
- wagtail/contrib/redirects/templates/wagtailredirects/results.html +0 -23
- wagtail/documents/templates/wagtaildocs/documents/list.html +0 -2
- wagtail/search/tests/test_postgres_stemming.py +0 -40
- wagtail/sites/templates/wagtailsites/create.html +0 -6
- wagtail/sites/templates/wagtailsites/edit.html +0 -6
- wagtail/snippets/templates/wagtailsnippets/snippets/revisions/_actions.html +0 -36
- wagtail/users/templates/wagtailusers/users/list.html +0 -62
- wagtail/users/urls/users.py +0 -12
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/LICENSE +0 -0
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/WHEEL +0 -0
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-6.0.2.dist-info → wagtail-6.1rc1.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ msgid ""
|
|
|
8
8
|
msgstr ""
|
|
9
9
|
"Project-Id-Version: PACKAGE VERSION\n"
|
|
10
10
|
"Report-Msgid-Bugs-To: \n"
|
|
11
|
-
"POT-Creation-Date: 2024-
|
|
11
|
+
"POT-Creation-Date: 2024-04-18 17:28+0100\n"
|
|
12
12
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
13
13
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
14
14
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
wagtail/locales/tests.py
CHANGED
|
@@ -20,7 +20,10 @@ class TestLocaleIndexView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
20
20
|
response = self.get()
|
|
21
21
|
self.assertEqual(response.status_code, 200)
|
|
22
22
|
self.assertTemplateUsed(response, "wagtailadmin/generic/index.html")
|
|
23
|
-
self.
|
|
23
|
+
self.assertBreadcrumbsItemsRendered(
|
|
24
|
+
[{"url": "", "label": "Locales"}],
|
|
25
|
+
response.content,
|
|
26
|
+
)
|
|
24
27
|
|
|
25
28
|
|
|
26
29
|
class TestLocaleCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
@@ -43,7 +46,13 @@ class TestLocaleCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
43
46
|
response = self.get()
|
|
44
47
|
self.assertEqual(response.status_code, 200)
|
|
45
48
|
self.assertTemplateUsed(response, "wagtaillocales/create.html")
|
|
46
|
-
self.
|
|
49
|
+
self.assertBreadcrumbsItemsRendered(
|
|
50
|
+
[
|
|
51
|
+
{"label": "Locales", "url": "/admin/locales/"},
|
|
52
|
+
{"label": "New: Locale", "url": ""},
|
|
53
|
+
],
|
|
54
|
+
response.content,
|
|
55
|
+
)
|
|
47
56
|
|
|
48
57
|
self.assertEqual(
|
|
49
58
|
response.context["form"].fields["language_code"].choices, [("fr", "French")]
|
|
@@ -116,7 +125,13 @@ class TestLocaleEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
|
|
|
116
125
|
response = self.get()
|
|
117
126
|
self.assertEqual(response.status_code, 200)
|
|
118
127
|
self.assertTemplateUsed(response, "wagtaillocales/edit.html")
|
|
119
|
-
self.
|
|
128
|
+
self.assertBreadcrumbsItemsRendered(
|
|
129
|
+
[
|
|
130
|
+
{"url": "/admin/locales/", "label": "Locales"},
|
|
131
|
+
{"url": "", "label": str(self.english)},
|
|
132
|
+
],
|
|
133
|
+
response.content,
|
|
134
|
+
)
|
|
120
135
|
|
|
121
136
|
self.assertEqual(
|
|
122
137
|
response.context["form"].fields["language_code"].choices,
|
wagtail/locales/views.py
CHANGED
|
@@ -38,7 +38,9 @@ class Command(BaseCommand):
|
|
|
38
38
|
|
|
39
39
|
with transaction.atomic():
|
|
40
40
|
with disable_reference_index_auto_update():
|
|
41
|
-
|
|
41
|
+
# Use `_raw_delete` to avoid loading instances into memory
|
|
42
|
+
all_references = ReferenceIndex.objects.all()
|
|
43
|
+
all_references._raw_delete(using=all_references.db)
|
|
42
44
|
|
|
43
45
|
for model in apps.get_models():
|
|
44
46
|
if not ReferenceIndex.is_indexed(model):
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Generated by Django 4.2.7 on 2024-02-01 21:21
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('wagtailcore', '0091_remove_revision_submitted_for_moderation'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='collectionviewrestriction',
|
|
15
|
+
name='password',
|
|
16
|
+
field=models.CharField(blank=True, help_text='Shared passwords should not be used to protect sensitive content. Anyone who has this password will be able to view the content.', max_length=255, verbose_name='shared password'),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='collectionviewrestriction',
|
|
20
|
+
name='restriction_type',
|
|
21
|
+
field=models.CharField(choices=[('none', 'Public'), ('password', 'Private, accessible with a shared password'), ('login', 'Private, accessible to any logged-in users'), ('groups', 'Private, accessible to users in specific groups')], max_length=20),
|
|
22
|
+
),
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='pageviewrestriction',
|
|
25
|
+
name='password',
|
|
26
|
+
field=models.CharField(blank=True, help_text='Shared passwords should not be used to protect sensitive content. Anyone who has this password will be able to view the content.', max_length=255, verbose_name='shared password'),
|
|
27
|
+
),
|
|
28
|
+
migrations.AlterField(
|
|
29
|
+
model_name='pageviewrestriction',
|
|
30
|
+
name='restriction_type',
|
|
31
|
+
field=models.CharField(choices=[('none', 'Public'), ('password', 'Private, accessible with a shared password'), ('login', 'Private, accessible to any logged-in users'), ('groups', 'Private, accessible to users in specific groups')], max_length=20),
|
|
32
|
+
),
|
|
33
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Generated by Django 4.2.7 on 2024-02-12 21:04
|
|
2
|
+
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
import django.db.models.deletion
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
12
|
+
("contenttypes", "0002_remove_content_type_name"),
|
|
13
|
+
("wagtailcore", "0092_alter_collectionviewrestriction_password_and_more"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
operations = [
|
|
17
|
+
migrations.CreateModel(
|
|
18
|
+
name="UploadedFile",
|
|
19
|
+
fields=[
|
|
20
|
+
(
|
|
21
|
+
"id",
|
|
22
|
+
models.AutoField(
|
|
23
|
+
auto_created=True,
|
|
24
|
+
primary_key=True,
|
|
25
|
+
serialize=False,
|
|
26
|
+
verbose_name="ID",
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
("file", models.FileField(max_length=200, upload_to="wagtail_uploads")),
|
|
30
|
+
(
|
|
31
|
+
"for_content_type",
|
|
32
|
+
models.ForeignKey(
|
|
33
|
+
null=True,
|
|
34
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
35
|
+
related_name="uploads",
|
|
36
|
+
to="contenttypes.contenttype",
|
|
37
|
+
verbose_name="for content type",
|
|
38
|
+
),
|
|
39
|
+
),
|
|
40
|
+
(
|
|
41
|
+
"uploaded_by_user",
|
|
42
|
+
models.ForeignKey(
|
|
43
|
+
blank=True,
|
|
44
|
+
editable=False,
|
|
45
|
+
null=True,
|
|
46
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
47
|
+
to=settings.AUTH_USER_MODEL,
|
|
48
|
+
verbose_name="uploaded by user",
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
],
|
|
52
|
+
),
|
|
53
|
+
]
|
wagtail/models/__init__.py
CHANGED
|
@@ -9,12 +9,16 @@ should implement low-level generic functionality which is then imported by highe
|
|
|
9
9
|
as Page.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
12
14
|
import functools
|
|
13
15
|
import logging
|
|
14
16
|
import posixpath
|
|
15
17
|
import uuid
|
|
16
18
|
from io import StringIO
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
17
20
|
from urllib.parse import urlparse
|
|
21
|
+
from warnings import warn
|
|
18
22
|
|
|
19
23
|
from django import forms
|
|
20
24
|
from django.conf import settings
|
|
@@ -92,6 +96,7 @@ from wagtail.signals import (
|
|
|
92
96
|
workflow_submitted,
|
|
93
97
|
)
|
|
94
98
|
from wagtail.url_routing import RouteResult
|
|
99
|
+
from wagtail.utils.deprecation import RemovedInWagtail70Warning
|
|
95
100
|
from wagtail.utils.timestamps import ensure_utc
|
|
96
101
|
|
|
97
102
|
from .audit_log import ( # noqa: F401
|
|
@@ -100,16 +105,6 @@ from .audit_log import ( # noqa: F401
|
|
|
100
105
|
LogEntryQuerySet,
|
|
101
106
|
ModelLogEntry,
|
|
102
107
|
)
|
|
103
|
-
from .collections import ( # noqa: F401
|
|
104
|
-
BaseCollectionManager,
|
|
105
|
-
Collection,
|
|
106
|
-
CollectionManager,
|
|
107
|
-
CollectionMember,
|
|
108
|
-
CollectionViewRestriction,
|
|
109
|
-
GroupCollectionPermission,
|
|
110
|
-
GroupCollectionPermissionManager,
|
|
111
|
-
get_root_collection_id,
|
|
112
|
-
)
|
|
113
108
|
from .copying import _copy, _copy_m2m_relations, _extract_field_data # noqa: F401
|
|
114
109
|
from .i18n import ( # noqa: F401
|
|
115
110
|
BootstrapTranslatableMixin,
|
|
@@ -120,11 +115,25 @@ from .i18n import ( # noqa: F401
|
|
|
120
115
|
bootstrap_translatable_model,
|
|
121
116
|
get_translatable_models,
|
|
122
117
|
)
|
|
118
|
+
from .media import ( # noqa: F401
|
|
119
|
+
BaseCollectionManager,
|
|
120
|
+
Collection,
|
|
121
|
+
CollectionManager,
|
|
122
|
+
CollectionMember,
|
|
123
|
+
CollectionViewRestriction,
|
|
124
|
+
GroupCollectionPermission,
|
|
125
|
+
GroupCollectionPermissionManager,
|
|
126
|
+
UploadedFile,
|
|
127
|
+
get_root_collection_id,
|
|
128
|
+
)
|
|
123
129
|
from .reference_index import ReferenceIndex # noqa: F401
|
|
124
130
|
from .sites import Site, SiteManager, SiteRootPath # noqa: F401
|
|
125
131
|
from .specific import SpecificMixin
|
|
126
132
|
from .view_restrictions import BaseViewRestriction
|
|
127
133
|
|
|
134
|
+
if TYPE_CHECKING:
|
|
135
|
+
from django.http import HttpRequest
|
|
136
|
+
|
|
128
137
|
logger = logging.getLogger("wagtail")
|
|
129
138
|
|
|
130
139
|
PAGE_TEMPLATE_VAR = "page"
|
|
@@ -1266,7 +1275,6 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
|
|
|
1266
1275
|
exclude_fields_in_copy = []
|
|
1267
1276
|
default_exclude_fields_in_copy = [
|
|
1268
1277
|
"id",
|
|
1269
|
-
"path",
|
|
1270
1278
|
"depth",
|
|
1271
1279
|
"numchild",
|
|
1272
1280
|
"url_path",
|
|
@@ -1283,6 +1291,43 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
|
|
|
1283
1291
|
promote_panels = []
|
|
1284
1292
|
settings_panels = []
|
|
1285
1293
|
|
|
1294
|
+
@staticmethod
|
|
1295
|
+
def route_for_request(request: "HttpRequest", path: str) -> RouteResult | None:
|
|
1296
|
+
"""
|
|
1297
|
+
Find the page route for the given HTTP request object, and URL path. The route
|
|
1298
|
+
result (`page`, `args`, and `kwargs`) will be cached via
|
|
1299
|
+
`request._wagtail_route_for_request`.
|
|
1300
|
+
"""
|
|
1301
|
+
if not hasattr(request, "_wagtail_route_for_request"):
|
|
1302
|
+
try:
|
|
1303
|
+
# we need a valid Site object for this request in order to proceed
|
|
1304
|
+
if site := Site.find_for_request(request):
|
|
1305
|
+
path_components = [
|
|
1306
|
+
component for component in path.split("/") if component
|
|
1307
|
+
]
|
|
1308
|
+
request._wagtail_route_for_request = (
|
|
1309
|
+
site.root_page.localized.specific.route(
|
|
1310
|
+
request, path_components
|
|
1311
|
+
)
|
|
1312
|
+
)
|
|
1313
|
+
else:
|
|
1314
|
+
request._wagtail_route_for_request = None
|
|
1315
|
+
except Http404:
|
|
1316
|
+
# .route() can raise Http404
|
|
1317
|
+
request._wagtail_route_for_request = None
|
|
1318
|
+
|
|
1319
|
+
return request._wagtail_route_for_request
|
|
1320
|
+
|
|
1321
|
+
@staticmethod
|
|
1322
|
+
def find_for_request(request: "HttpRequest", path: str) -> "Page" | None:
|
|
1323
|
+
"""
|
|
1324
|
+
Find the page for the given HTTP request object, and URL path. The full
|
|
1325
|
+
page route will be cached via `request._wagtail_route_for_request`
|
|
1326
|
+
"""
|
|
1327
|
+
result = Page.route_for_request(request, path)
|
|
1328
|
+
if result is not None:
|
|
1329
|
+
return result[0]
|
|
1330
|
+
|
|
1286
1331
|
def __init__(self, *args, **kwargs):
|
|
1287
1332
|
super().__init__(*args, **kwargs)
|
|
1288
1333
|
if not self.id:
|
|
@@ -1625,6 +1670,11 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
|
|
|
1625
1670
|
|
|
1626
1671
|
try:
|
|
1627
1672
|
subpage = self.get_children().get(slug=child_slug)
|
|
1673
|
+
# Cache the parent page on the subpage to avoid another db query
|
|
1674
|
+
# Treebeard's get_parent will use the `_cached_parent_obj` attribute if it exists
|
|
1675
|
+
# And update = False
|
|
1676
|
+
setattr(subpage, "_cached_parent_obj", self)
|
|
1677
|
+
|
|
1628
1678
|
except Page.DoesNotExist:
|
|
1629
1679
|
raise Http404
|
|
1630
1680
|
|
|
@@ -2549,9 +2599,7 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
|
|
|
2549
2599
|
|
|
2550
2600
|
return PageViewRestriction.objects.filter(page_id__in=page_ids_to_check)
|
|
2551
2601
|
|
|
2552
|
-
password_required_template =
|
|
2553
|
-
settings, "PASSWORD_REQUIRED_TEMPLATE", "wagtailcore/password_required.html"
|
|
2554
|
-
)
|
|
2602
|
+
password_required_template = None
|
|
2555
2603
|
|
|
2556
2604
|
def serve_password_required_response(self, request, form, action_url):
|
|
2557
2605
|
"""
|
|
@@ -2561,10 +2609,32 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase):
|
|
|
2561
2609
|
(and zero or more hidden fields that also need to be output on the template)
|
|
2562
2610
|
action_url = URL that this form should be POSTed to
|
|
2563
2611
|
"""
|
|
2612
|
+
|
|
2613
|
+
password_required_template = self.password_required_template
|
|
2614
|
+
|
|
2615
|
+
if not password_required_template:
|
|
2616
|
+
password_required_template = getattr(
|
|
2617
|
+
settings,
|
|
2618
|
+
"WAGTAIL_PASSWORD_REQUIRED_TEMPLATE",
|
|
2619
|
+
"wagtailcore/password_required.html",
|
|
2620
|
+
)
|
|
2621
|
+
|
|
2622
|
+
if hasattr(settings, "PASSWORD_REQUIRED_TEMPLATE"):
|
|
2623
|
+
warn(
|
|
2624
|
+
"The `PASSWORD_REQUIRED_TEMPLATE` setting is deprecated - use `WAGTAIL_PASSWORD_REQUIRED_TEMPLATE` instead.",
|
|
2625
|
+
category=RemovedInWagtail70Warning,
|
|
2626
|
+
)
|
|
2627
|
+
|
|
2628
|
+
password_required_template = getattr(
|
|
2629
|
+
settings,
|
|
2630
|
+
"PASSWORD_REQUIRED_TEMPLATE",
|
|
2631
|
+
password_required_template,
|
|
2632
|
+
)
|
|
2633
|
+
|
|
2564
2634
|
context = self.get_context(request)
|
|
2565
2635
|
context["form"] = form
|
|
2566
2636
|
context["action_url"] = action_url
|
|
2567
|
-
return TemplateResponse(request,
|
|
2637
|
+
return TemplateResponse(request, password_required_template, context)
|
|
2568
2638
|
|
|
2569
2639
|
def with_content_json(self, content):
|
|
2570
2640
|
"""
|
|
@@ -2727,7 +2797,31 @@ class RevisionQuerySet(models.QuerySet):
|
|
|
2727
2797
|
)
|
|
2728
2798
|
|
|
2729
2799
|
|
|
2730
|
-
RevisionsManager
|
|
2800
|
+
class RevisionsManager(models.Manager.from_queryset(RevisionQuerySet)):
|
|
2801
|
+
def previous_revision_id_subquery(self, revision_fk_name="revision"):
|
|
2802
|
+
"""
|
|
2803
|
+
Returns a Subquery that can be used to annotate a queryset with the ID
|
|
2804
|
+
of the previous revision, based on the revision_fk_name field. Useful
|
|
2805
|
+
to avoid N+1 queries when generating comparison links between revisions.
|
|
2806
|
+
|
|
2807
|
+
The logic is similar to Revision.get_previous().pk.
|
|
2808
|
+
"""
|
|
2809
|
+
fk = revision_fk_name
|
|
2810
|
+
return Subquery(
|
|
2811
|
+
Revision.objects.filter(
|
|
2812
|
+
base_content_type_id=OuterRef(f"{fk}__base_content_type_id"),
|
|
2813
|
+
object_id=OuterRef(f"{fk}__object_id"),
|
|
2814
|
+
)
|
|
2815
|
+
.filter(
|
|
2816
|
+
Q(
|
|
2817
|
+
created_at=OuterRef(f"{fk}__created_at"),
|
|
2818
|
+
pk__lt=OuterRef(f"{fk}__pk"),
|
|
2819
|
+
)
|
|
2820
|
+
| Q(created_at__lt=OuterRef(f"{fk}__created_at"))
|
|
2821
|
+
)
|
|
2822
|
+
.order_by("-created_at", "-pk")
|
|
2823
|
+
.values_list("pk", flat=True)[:1]
|
|
2824
|
+
)
|
|
2731
2825
|
|
|
2732
2826
|
|
|
2733
2827
|
class PageRevisionsManager(RevisionsManager):
|
|
@@ -3520,7 +3614,7 @@ class WorkflowManager(models.Manager):
|
|
|
3520
3614
|
return self.filter(active=True)
|
|
3521
3615
|
|
|
3522
3616
|
|
|
3523
|
-
class
|
|
3617
|
+
class AbstractWorkflow(ClusterableModel):
|
|
3524
3618
|
name = models.CharField(max_length=255, verbose_name=_("name"))
|
|
3525
3619
|
active = models.BooleanField(
|
|
3526
3620
|
verbose_name=_("active"),
|
|
@@ -3609,9 +3703,14 @@ class Workflow(ClusterableModel):
|
|
|
3609
3703
|
class Meta:
|
|
3610
3704
|
verbose_name = _("workflow")
|
|
3611
3705
|
verbose_name_plural = _("workflows")
|
|
3706
|
+
abstract = True
|
|
3612
3707
|
|
|
3613
3708
|
|
|
3614
|
-
class
|
|
3709
|
+
class Workflow(AbstractWorkflow):
|
|
3710
|
+
pass
|
|
3711
|
+
|
|
3712
|
+
|
|
3713
|
+
class AbstractGroupApprovalTask(Task):
|
|
3615
3714
|
groups = models.ManyToManyField(
|
|
3616
3715
|
Group,
|
|
3617
3716
|
verbose_name=_("groups"),
|
|
@@ -3643,24 +3742,37 @@ class GroupApprovalTask(Task):
|
|
|
3643
3742
|
|
|
3644
3743
|
return super().start(workflow_state, user=user)
|
|
3645
3744
|
|
|
3745
|
+
def _user_in_groups(self, user):
|
|
3746
|
+
# Cache the check whether "this user is in any of this
|
|
3747
|
+
# GroupApprovalTask's groups" on the user object, in case we do it
|
|
3748
|
+
# against the same user and task multiple times in a request.
|
|
3749
|
+
# Use a dict to map the task id to the check result, in case we also
|
|
3750
|
+
# check against different GroupApprovalTasks for the same user.
|
|
3751
|
+
cache_attr = "_group_approval_task_checks"
|
|
3752
|
+
if not (checks_cache := getattr(user, cache_attr, {})):
|
|
3753
|
+
setattr(user, cache_attr, checks_cache)
|
|
3754
|
+
|
|
3755
|
+
if self.pk not in checks_cache:
|
|
3756
|
+
checks_cache[self.pk] = self.groups.filter(
|
|
3757
|
+
id__in=user.groups.all()
|
|
3758
|
+
).exists()
|
|
3759
|
+
|
|
3760
|
+
return checks_cache[self.pk]
|
|
3761
|
+
|
|
3646
3762
|
def user_can_access_editor(self, obj, user):
|
|
3647
|
-
return (
|
|
3648
|
-
self.groups.filter(id__in=user.groups.all()).exists() or user.is_superuser
|
|
3649
|
-
)
|
|
3763
|
+
return user.is_superuser or self._user_in_groups(user)
|
|
3650
3764
|
|
|
3651
3765
|
def locked_for_user(self, obj, user):
|
|
3652
|
-
return not (
|
|
3653
|
-
self.groups.filter(id__in=user.groups.all()).exists() or user.is_superuser
|
|
3654
|
-
)
|
|
3766
|
+
return not (user.is_superuser or self._user_in_groups(user))
|
|
3655
3767
|
|
|
3656
3768
|
def user_can_lock(self, obj, user):
|
|
3657
|
-
return self.
|
|
3769
|
+
return self._user_in_groups(user)
|
|
3658
3770
|
|
|
3659
3771
|
def user_can_unlock(self, obj, user):
|
|
3660
3772
|
return False
|
|
3661
3773
|
|
|
3662
3774
|
def get_actions(self, obj, user):
|
|
3663
|
-
if
|
|
3775
|
+
if user.is_superuser or self._user_in_groups(user):
|
|
3664
3776
|
return [
|
|
3665
3777
|
("reject", _("Request changes"), True),
|
|
3666
3778
|
("approve", _("Approve"), False),
|
|
@@ -3670,10 +3782,8 @@ class GroupApprovalTask(Task):
|
|
|
3670
3782
|
return []
|
|
3671
3783
|
|
|
3672
3784
|
def get_task_states_user_can_moderate(self, user, **kwargs):
|
|
3673
|
-
if
|
|
3674
|
-
return
|
|
3675
|
-
status=TaskState.STATUS_IN_PROGRESS, task=self.task_ptr
|
|
3676
|
-
)
|
|
3785
|
+
if user.is_superuser or self._user_in_groups(user):
|
|
3786
|
+
return self.task_states.filter(status=TaskState.STATUS_IN_PROGRESS)
|
|
3677
3787
|
else:
|
|
3678
3788
|
return TaskState.objects.none()
|
|
3679
3789
|
|
|
@@ -3682,10 +3792,15 @@ class GroupApprovalTask(Task):
|
|
|
3682
3792
|
return _("Members of the chosen Wagtail Groups can approve this task")
|
|
3683
3793
|
|
|
3684
3794
|
class Meta:
|
|
3795
|
+
abstract = True
|
|
3685
3796
|
verbose_name = _("Group approval task")
|
|
3686
3797
|
verbose_name_plural = _("Group approval tasks")
|
|
3687
3798
|
|
|
3688
3799
|
|
|
3800
|
+
class GroupApprovalTask(AbstractGroupApprovalTask):
|
|
3801
|
+
pass
|
|
3802
|
+
|
|
3803
|
+
|
|
3689
3804
|
class WorkflowStateQuerySet(models.QuerySet):
|
|
3690
3805
|
def active(self):
|
|
3691
3806
|
"""
|
|
@@ -4118,10 +4233,10 @@ class WorkflowState(models.Model):
|
|
|
4118
4233
|
|
|
4119
4234
|
class BaseTaskStateManager(models.Manager):
|
|
4120
4235
|
def reviewable_by(self, user):
|
|
4121
|
-
tasks = Task.objects.filter(active=True)
|
|
4236
|
+
tasks = Task.objects.filter(active=True).specific()
|
|
4122
4237
|
states = TaskState.objects.none()
|
|
4123
4238
|
for task in tasks:
|
|
4124
|
-
states = states | task.
|
|
4239
|
+
states = states | task.get_task_states_user_can_moderate(user=user)
|
|
4125
4240
|
return states
|
|
4126
4241
|
|
|
4127
4242
|
|
wagtail/models/i18n.py
CHANGED
|
@@ -378,7 +378,7 @@ def bootstrap_translatable_model(model, locale):
|
|
|
378
378
|
This function populates the "translation_key", and "locale" fields on model instances that were created
|
|
379
379
|
before wagtail-localize was added to the site.
|
|
380
380
|
|
|
381
|
-
This can be called from a data migration, or instead you could use the "
|
|
381
|
+
This can be called from a data migration, or instead you could use the "bootstrap_translatable_models"
|
|
382
382
|
management command.
|
|
383
383
|
"""
|
|
384
384
|
for instance in (
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
from django.conf import settings
|
|
1
2
|
from django.contrib.auth.models import Group, Permission
|
|
3
|
+
from django.contrib.contenttypes.models import ContentType
|
|
2
4
|
from django.db import models
|
|
3
5
|
from django.utils.html import format_html
|
|
4
6
|
from django.utils.safestring import mark_safe
|
|
@@ -12,13 +14,16 @@ from .view_restrictions import BaseViewRestriction
|
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class CollectionQuerySet(TreeQuerySet):
|
|
17
|
+
def get_min_depth(self):
|
|
18
|
+
return self.aggregate(models.Min("depth"))["depth__min"] or 2
|
|
19
|
+
|
|
15
20
|
def get_indented_choices(self):
|
|
16
21
|
"""
|
|
17
22
|
Return a list of (id, label) tuples for use as a list of choices in a collection chooser
|
|
18
23
|
dropdown, where the label is formatted with get_indented_name to provide a tree layout.
|
|
19
24
|
The indent level is chosen to place the minimum-depth collection at indent 0.
|
|
20
25
|
"""
|
|
21
|
-
min_depth = self.
|
|
26
|
+
min_depth = self.get_min_depth()
|
|
22
27
|
return [
|
|
23
28
|
(collection.pk, collection.get_indented_name(min_depth, html=True))
|
|
24
29
|
for collection in self
|
|
@@ -90,7 +95,7 @@ class Collection(MP_Node):
|
|
|
90
95
|
Renders this Collection's name as a formatted string that displays its hierarchical depth via indentation.
|
|
91
96
|
If indentation_start_depth is supplied, the Collection's depth is rendered relative to that depth.
|
|
92
97
|
indentation_start_depth defaults to 2, the depth of the first non-Root Collection.
|
|
93
|
-
Pass html=True to get
|
|
98
|
+
Pass html=True to get an HTML representation, instead of the default plain-text.
|
|
94
99
|
|
|
95
100
|
Example text output: " ↳ Pies"
|
|
96
101
|
Example HTML output: " ↳ Pies"
|
|
@@ -188,3 +193,29 @@ class GroupCollectionPermission(models.Model):
|
|
|
188
193
|
unique_together = ("group", "collection", "permission")
|
|
189
194
|
verbose_name = _("group collection permission")
|
|
190
195
|
verbose_name_plural = _("group collection permissions")
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class UploadedFile(models.Model):
|
|
199
|
+
"""
|
|
200
|
+
Temporary storage for media fields uploaded through the multiple image/document uploader.
|
|
201
|
+
When validation rules (e.g. required metadata fields) prevent creating an Image/Document object from the file alone.
|
|
202
|
+
In this case, the file is stored against this model, to be turned into an Image/Document object once the full form
|
|
203
|
+
has been filled in.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
for_content_type = models.ForeignKey(
|
|
207
|
+
ContentType,
|
|
208
|
+
verbose_name=_("for content type"),
|
|
209
|
+
related_name="uploads",
|
|
210
|
+
on_delete=models.CASCADE,
|
|
211
|
+
null=True,
|
|
212
|
+
)
|
|
213
|
+
file = models.FileField(upload_to="wagtail_uploads", max_length=200)
|
|
214
|
+
uploaded_by_user = models.ForeignKey(
|
|
215
|
+
settings.AUTH_USER_MODEL,
|
|
216
|
+
verbose_name=_("uploaded by user"),
|
|
217
|
+
null=True,
|
|
218
|
+
blank=True,
|
|
219
|
+
editable=False,
|
|
220
|
+
on_delete=models.SET_NULL,
|
|
221
|
+
)
|
|
@@ -160,7 +160,7 @@ class ReferenceIndex(models.Model):
|
|
|
160
160
|
# linked by a ParentalKey.
|
|
161
161
|
tracked_models = set()
|
|
162
162
|
|
|
163
|
-
#
|
|
163
|
+
# The set of models that can appear as the 'from' object in the reference index.
|
|
164
164
|
# This only includes those registered with `register_model`, and NOT child models linked
|
|
165
165
|
# by ParentalKey (object references on those are recorded under the parent).
|
|
166
166
|
indexed_models = set()
|
|
@@ -19,13 +19,20 @@ class BaseViewRestriction(models.Model):
|
|
|
19
19
|
|
|
20
20
|
RESTRICTION_CHOICES = (
|
|
21
21
|
(NONE, _("Public")),
|
|
22
|
-
(
|
|
23
|
-
(
|
|
22
|
+
(PASSWORD, _("Private, accessible with a shared password")),
|
|
23
|
+
(LOGIN, _("Private, accessible to any logged-in users")),
|
|
24
24
|
(GROUPS, _("Private, accessible to users in specific groups")),
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
restriction_type = models.CharField(max_length=20, choices=RESTRICTION_CHOICES)
|
|
28
|
-
password = models.CharField(
|
|
28
|
+
password = models.CharField(
|
|
29
|
+
verbose_name=_("shared password"),
|
|
30
|
+
max_length=255,
|
|
31
|
+
blank=True,
|
|
32
|
+
help_text=_(
|
|
33
|
+
"Shared passwords should not be used to protect sensitive content. Anyone who has this password will be able to view the content."
|
|
34
|
+
),
|
|
35
|
+
)
|
|
29
36
|
groups = models.ManyToManyField(Group, verbose_name=_("groups"), blank=True)
|
|
30
37
|
|
|
31
38
|
def accept_request(self, request):
|
|
@@ -172,3 +172,9 @@ WAGTAILSEARCH_BACKENDS = {
|
|
|
172
172
|
# Base URL to use when referring to full URLs within the Wagtail admin backend -
|
|
173
173
|
# e.g. in notification emails. Don't include '/admin' or a trailing slash
|
|
174
174
|
WAGTAILADMIN_BASE_URL = "http://example.com"
|
|
175
|
+
|
|
176
|
+
# Allowed file extensions for documents in the document library.
|
|
177
|
+
# This can be omitted to allow all files, but note that this may present a security risk
|
|
178
|
+
# if untrusted users are allowed to upload files -
|
|
179
|
+
# see https://docs.wagtail.org/en/stable/advanced_topics/deploying.html#user-uploaded-files
|
|
180
|
+
WAGTAILDOCS_EXTENSIONS = ['csv', 'docx', 'key', 'odt', 'pdf', 'pptx', 'rtf', 'txt', 'xlsx', 'zip']
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
Django>=4.2,<5.1
|
|
2
|
-
wagtail
|
|
2
|
+
wagtail==6.1rc1
|
wagtail/rich_text/__init__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from functools import lru_cache
|
|
3
3
|
from html import unescape
|
|
4
|
+
from typing import List
|
|
4
5
|
|
|
5
6
|
from django.core.validators import MaxLengthValidator
|
|
6
7
|
from django.db.models import Model
|
|
@@ -26,23 +27,23 @@ def get_rewriter():
|
|
|
26
27
|
return MultiRuleRewriter(
|
|
27
28
|
[
|
|
28
29
|
LinkRewriter(
|
|
29
|
-
{
|
|
30
|
-
linktype: handler.
|
|
30
|
+
bulk_rules={
|
|
31
|
+
linktype: handler.expand_db_attributes_many
|
|
31
32
|
for linktype, handler in link_rules.items()
|
|
32
33
|
},
|
|
33
|
-
{
|
|
34
|
+
reference_extractors={
|
|
34
35
|
linktype: handler.extract_references
|
|
35
36
|
for linktype, handler in link_rules.items()
|
|
36
37
|
},
|
|
37
38
|
),
|
|
38
39
|
EmbedRewriter(
|
|
39
|
-
{
|
|
40
|
-
embedtype: handler.
|
|
40
|
+
bulk_rules={
|
|
41
|
+
embedtype: handler.expand_db_attributes_many
|
|
41
42
|
for embedtype, handler in embed_rules.items()
|
|
42
43
|
},
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
for
|
|
44
|
+
reference_extractors={
|
|
45
|
+
embedtype: handler.extract_references
|
|
46
|
+
for embedtype, handler in embed_rules.items()
|
|
46
47
|
},
|
|
47
48
|
),
|
|
48
49
|
]
|
|
@@ -130,6 +131,14 @@ class EntityHandler:
|
|
|
130
131
|
model = cls.get_model()
|
|
131
132
|
return model._default_manager.get(id=attrs["id"])
|
|
132
133
|
|
|
134
|
+
@classmethod
|
|
135
|
+
def get_many(cls, attrs_list: List[dict]) -> List[Model]:
|
|
136
|
+
model = cls.get_model()
|
|
137
|
+
instance_ids = [attrs.get("id") for attrs in attrs_list]
|
|
138
|
+
instances_by_id = model._default_manager.in_bulk(instance_ids)
|
|
139
|
+
instances_by_str_id = {str(k): v for k, v in instances_by_id.items()}
|
|
140
|
+
return [instances_by_str_id.get(str(id_)) for id_ in instance_ids]
|
|
141
|
+
|
|
133
142
|
@staticmethod
|
|
134
143
|
def expand_db_attributes(attrs: dict) -> str:
|
|
135
144
|
"""
|
|
@@ -138,6 +147,14 @@ class EntityHandler:
|
|
|
138
147
|
"""
|
|
139
148
|
raise NotImplementedError
|
|
140
149
|
|
|
150
|
+
@classmethod
|
|
151
|
+
def expand_db_attributes_many(cls, attrs_list: List[dict]) -> List[str]:
|
|
152
|
+
"""
|
|
153
|
+
Given a list of attribute dicts from a list of entity tags stored in
|
|
154
|
+
the database, return the real HTML representation of each one.
|
|
155
|
+
"""
|
|
156
|
+
return list(map(cls.expand_db_attributes, attrs_list))
|
|
157
|
+
|
|
141
158
|
@classmethod
|
|
142
159
|
def extract_references(cls, attrs):
|
|
143
160
|
"""
|