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
|
@@ -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-07-19 16:26+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"
|
|
@@ -51,31 +51,31 @@ msgstr ""
|
|
|
51
51
|
msgid "Select documents in choosers"
|
|
52
52
|
msgstr ""
|
|
53
53
|
|
|
54
|
-
#: models.py:
|
|
54
|
+
#: models.py:26
|
|
55
55
|
msgid "title"
|
|
56
56
|
msgstr ""
|
|
57
57
|
|
|
58
|
-
#: models.py:
|
|
58
|
+
#: models.py:27
|
|
59
59
|
msgid "file"
|
|
60
60
|
msgstr ""
|
|
61
61
|
|
|
62
|
-
#: models.py:
|
|
62
|
+
#: models.py:28
|
|
63
63
|
msgid "created at"
|
|
64
64
|
msgstr ""
|
|
65
65
|
|
|
66
|
-
#: models.py:
|
|
66
|
+
#: models.py:31
|
|
67
67
|
msgid "uploaded by user"
|
|
68
68
|
msgstr ""
|
|
69
69
|
|
|
70
|
-
#: models.py:
|
|
70
|
+
#: models.py:39
|
|
71
71
|
msgid "tags"
|
|
72
72
|
msgstr ""
|
|
73
73
|
|
|
74
|
-
#: models.py:
|
|
74
|
+
#: models.py:208
|
|
75
75
|
msgid "document"
|
|
76
76
|
msgstr ""
|
|
77
77
|
|
|
78
|
-
#: models.py:
|
|
78
|
+
#: models.py:209
|
|
79
79
|
msgid "documents"
|
|
80
80
|
msgstr ""
|
|
81
81
|
|
|
Binary file
|
|
@@ -252,6 +252,26 @@ msgstr ""
|
|
|
252
252
|
"Naložen ni še noben dokument. Zakaj ga ne bi <a "
|
|
253
253
|
"href=\"%(wagtaildocs_add_document_url)s\">naložili</a> sedaj?"
|
|
254
254
|
|
|
255
|
+
#, python-format
|
|
256
|
+
msgid ""
|
|
257
|
+
"<span>%(total)s</span> Document <span class=\"w-sr-only\">created in "
|
|
258
|
+
"%(site_name)s</span>"
|
|
259
|
+
msgid_plural ""
|
|
260
|
+
"<span>%(total)s</span> Documents <span class=\"w-sr-only\">created in "
|
|
261
|
+
"%(site_name)s</span>"
|
|
262
|
+
msgstr[0] ""
|
|
263
|
+
"<span>%(total)s</span> dokument <span class=\"w-sr-only\"> ustvarjen v "
|
|
264
|
+
"%(site_name)s</span>"
|
|
265
|
+
msgstr[1] ""
|
|
266
|
+
"<span>%(total)s</span> dokumenta <span class=\"w-sr-only\">ustvarjena na "
|
|
267
|
+
"%(site_name)s</span>"
|
|
268
|
+
msgstr[2] ""
|
|
269
|
+
"<span>%(total)s</span> dokumenti <span class=\"w-sr-only\">ustvarjeni na "
|
|
270
|
+
"%(site_name)s</span>"
|
|
271
|
+
msgstr[3] ""
|
|
272
|
+
"<span>%(total)s</span> dokumentov <span class=\"w-sr-only\">narejenih v "
|
|
273
|
+
"%(site_name)s</span>"
|
|
274
|
+
|
|
255
275
|
msgid "Add multiple documents"
|
|
256
276
|
msgstr "Dodaj več dokumentov"
|
|
257
277
|
|
wagtail/documents/models.py
CHANGED
|
@@ -4,6 +4,7 @@ from contextlib import contextmanager
|
|
|
4
4
|
from mimetypes import guess_type
|
|
5
5
|
|
|
6
6
|
from django.conf import settings
|
|
7
|
+
from django.core.exceptions import ValidationError
|
|
7
8
|
from django.core.validators import FileExtensionValidator
|
|
8
9
|
from django.db import models
|
|
9
10
|
from django.dispatch import Signal
|
|
@@ -71,7 +72,10 @@ class AbstractDocument(CollectionMember, index.Indexed, models.Model):
|
|
|
71
72
|
allowed_extensions = getattr(settings, "WAGTAILDOCS_EXTENSIONS", None)
|
|
72
73
|
if allowed_extensions:
|
|
73
74
|
validate = FileExtensionValidator(allowed_extensions)
|
|
74
|
-
|
|
75
|
+
try:
|
|
76
|
+
validate(self.file)
|
|
77
|
+
except ValidationError as e:
|
|
78
|
+
raise ValidationError({"file": e.messages[0]})
|
|
75
79
|
|
|
76
80
|
def is_stored_locally(self):
|
|
77
81
|
"""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,o={4186:(e,o,r)=>{var t=r(1669),n=r.n(t),a=r(2614);class
|
|
1
|
+
(()=>{"use strict";var e,o={4186:(e,o,r)=>{var t=r(1669),n=r.n(t),a=r(2614);class i extends a.C4{ajaxifyLinks(e,o){super.ajaxifyLinks(e,o),n()("a.upload-one-now").on("click",(e=>{const o=n()("#id_collection_id").val();o&&n()("#id_document-chooser-upload-collection").val(o),e.preventDefault()}))}}window.DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS=new i({searchInputDelay:50,creationFormFileFieldSelector:"#id_document-chooser-upload-file",creationFormTitleFieldSelector:"#id_document-chooser-upload-title",creationFormTabSelector:"#tab-upload",creationFormEventName:"wagtail:documents-upload"}).getOnLoadHandlers();class l extends a.ZZ{onloadHandlers=window.DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS}window.DocumentChooserModal=l},1669:e=>{e.exports=jQuery}},r={};function t(e){var n=r[e];if(void 0!==n)return n.exports;var a=r[e]={exports:{}};return o[e](a,a.exports,t),a.exports}t.m=o,e=[],t.O=(o,r,n,a)=>{if(!r){var i=1/0;for(u=0;u<e.length;u++){for(var[r,n,a]=e[u],l=!0,d=0;d<r.length;d++)(!1&a||i>=a)&&Object.keys(t.O).every((e=>t.O[e](r[d])))?r.splice(d--,1):(l=!1,a<i&&(i=a));if(l){e.splice(u--,1);var c=n();void 0!==c&&(o=c)}}return o}a=a||0;for(var u=e.length;u>0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[r,n,a]},t.n=e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return t.d(o,{a:o}),o},t.d=(e,o)=>{for(var r in o)t.o(o,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.j=884,(()=>{var e={884:0};t.O.j=o=>0===e[o];var o=(o,r)=>{var n,a,[i,l,d]=r,c=0;if(i.some((o=>0!==e[o]))){for(n in l)t.o(l,n)&&(t.m[n]=l[n]);if(d)var u=d(t)}for(o&&o(r);c<i.length;c++)a=i[c],t.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return t.O(u)},r=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];r.forEach(o.bind(null,0)),r.push=o.bind(null,r.push.bind(r))})();var n=t.O(void 0,[321],(()=>t(4186)));n=t.O(n)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,o={3819:(e,o,r)=>{var t=r(9465);class n extends t.y{chooserModalClass=DocumentChooserModal}window.DocumentChooser=n;class a extends t._{widgetClass=n;chooserModalClass=DocumentChooserModal}window.telepath.register("wagtail.documents.widgets.DocumentChooser",a)},1669:e=>{e.exports=jQuery}},r={};function t(e){var n=r[e];if(void 0!==n)return n.exports;var a=r[e]={
|
|
1
|
+
(()=>{"use strict";var e,o={3819:(e,o,r)=>{var t=r(9465);class n extends t.y{chooserModalClass=DocumentChooserModal}window.DocumentChooser=n;class a extends t._{widgetClass=n;chooserModalClass=DocumentChooserModal}window.telepath.register("wagtail.documents.widgets.DocumentChooser",a)},1669:e=>{e.exports=jQuery}},r={};function t(e){var n=r[e];if(void 0!==n)return n.exports;var a=r[e]={exports:{}};return o[e](a,a.exports,t),a.exports}t.m=o,e=[],t.O=(o,r,n,a)=>{if(!r){var i=1/0;for(d=0;d<e.length;d++){for(var[r,n,a]=e[d],l=!0,s=0;s<r.length;s++)(!1&a||i>=a)&&Object.keys(t.O).every((e=>t.O[e](r[s])))?r.splice(s--,1):(l=!1,a<i&&(i=a));if(l){e.splice(d--,1);var u=n();void 0!==u&&(o=u)}}return o}a=a||0;for(var d=e.length;d>0&&e[d-1][2]>a;d--)e[d]=e[d-1];e[d]=[r,n,a]},t.n=e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return t.d(o,{a:o}),o},t.d=(e,o)=>{for(var r in o)t.o(o,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:o[r]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.j=556,(()=>{var e={556:0};t.O.j=o=>0===e[o];var o=(o,r)=>{var n,a,[i,l,s]=r,u=0;if(i.some((o=>0!==e[o]))){for(n in l)t.o(l,n)&&(t.m[n]=l[n]);if(s)var d=s(t)}for(o&&o(r);u<i.length;u++)a=i[u],t.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return t.O(d)},r=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];r.forEach(o.bind(null,0)),r.push=o.bind(null,r.push.bind(r))})();var n=t.O(void 0,[321],(()=>t(3819)));n=t.O(n)})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,r={7023:(e,r,o)=>{var t=o(9465);class n extends t.y{chooserModalClass=DocumentChooserModal}window.DocumentChooser=n,window.DocumentChooser=n},1669:e=>{e.exports=jQuery}},o={};function t(e){var n=o[e];if(void 0!==n)return n.exports;var a=o[e]={
|
|
1
|
+
(()=>{"use strict";var e,r={7023:(e,r,o)=>{var t=o(9465);class n extends t.y{chooserModalClass=DocumentChooserModal}window.DocumentChooser=n,window.DocumentChooser=n},1669:e=>{e.exports=jQuery}},o={};function t(e){var n=o[e];if(void 0!==n)return n.exports;var a=o[e]={exports:{}};return r[e](a,a.exports,t),a.exports}t.m=r,e=[],t.O=(r,o,n,a)=>{if(!o){var i=1/0;for(c=0;c<e.length;c++){for(var[o,n,a]=e[c],l=!0,s=0;s<o.length;s++)(!1&a||i>=a)&&Object.keys(t.O).every((e=>t.O[e](o[s])))?o.splice(s--,1):(l=!1,a<i&&(i=a));if(l){e.splice(c--,1);var u=n();void 0!==u&&(r=u)}}return r}a=a||0;for(var c=e.length;c>0&&e[c-1][2]>a;c--)e[c]=e[c-1];e[c]=[o,n,a]},t.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return t.d(r,{a:r}),r},t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.j=844,(()=>{var e={844:0};t.O.j=r=>0===e[r];var r=(r,o)=>{var n,a,[i,l,s]=o,u=0;if(i.some((r=>0!==e[r]))){for(n in l)t.o(l,n)&&(t.m[n]=l[n]);if(s)var c=s(t)}for(r&&r(o);u<i.length;u++)a=i[u],t.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return t.O(c)},o=globalThis.webpackChunkwagtail=globalThis.webpackChunkwagtail||[];o.forEach(r.bind(null,0)),o.push=r.bind(null,o.push.bind(o))})();var n=t.O(void 0,[321],(()=>t(7023)));n=t.O(n)})();
|
|
@@ -217,8 +217,12 @@ class TestDocumentValidateExtensions(TestCase):
|
|
|
217
217
|
creation when called full_clean. This specific testcase invalid
|
|
218
218
|
file extension is passed
|
|
219
219
|
"""
|
|
220
|
-
with self.assertRaises(ValidationError):
|
|
220
|
+
with self.assertRaises(ValidationError) as e:
|
|
221
221
|
self.document_invalid.full_clean()
|
|
222
|
+
expected_message = (
|
|
223
|
+
"File extension “doc” is not allowed. Allowed extensions are: pdf."
|
|
224
|
+
)
|
|
225
|
+
self.assertEqual(e.exception.message_dict["file"][0], expected_message)
|
|
222
226
|
|
|
223
227
|
def test_create_doc_valid_extension(self):
|
|
224
228
|
"""
|
wagtail/embeds/apps.py
CHANGED
wagtail/embeds/embeds.py
CHANGED
|
@@ -9,7 +9,18 @@ from .finders import get_finders
|
|
|
9
9
|
from .models import Embed
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def get_finder_for_embed(url, max_width=None, max_height=None):
|
|
13
|
+
for finder in get_finders():
|
|
14
|
+
if finder.accept(url):
|
|
15
|
+
kwargs = {}
|
|
16
|
+
if accepts_kwarg(finder.find_embed, "max_height"):
|
|
17
|
+
kwargs["max_height"] = max_height
|
|
18
|
+
return finder.find_embed(url, max_width=max_width, **kwargs)
|
|
19
|
+
|
|
20
|
+
raise EmbedUnsupportedProviderException
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_embed(url, max_width=None, max_height=None, finder=get_finder_for_embed):
|
|
13
24
|
embed_hash = get_embed_hash(url, max_width, max_height)
|
|
14
25
|
|
|
15
26
|
# Check database
|
|
@@ -18,19 +29,6 @@ def get_embed(url, max_width=None, max_height=None, finder=None):
|
|
|
18
29
|
except Embed.DoesNotExist:
|
|
19
30
|
pass
|
|
20
31
|
|
|
21
|
-
# Get/Call finder
|
|
22
|
-
if not finder:
|
|
23
|
-
|
|
24
|
-
def finder(url, max_width=None, max_height=None):
|
|
25
|
-
for finder in get_finders():
|
|
26
|
-
if finder.accept(url):
|
|
27
|
-
kwargs = {}
|
|
28
|
-
if accepts_kwarg(finder.find_embed, "max_height"):
|
|
29
|
-
kwargs["max_height"] = max_height
|
|
30
|
-
return finder.find_embed(url, max_width=max_width, **kwargs)
|
|
31
|
-
|
|
32
|
-
raise EmbedUnsupportedProviderException
|
|
33
|
-
|
|
34
32
|
embed_dict = finder(url, max_width, max_height)
|
|
35
33
|
|
|
36
34
|
# Make sure width and height are valid integers before inserting into database
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import re
|
|
3
2
|
from urllib import request as urllib_request
|
|
4
3
|
from urllib.error import HTTPError, URLError
|
|
5
4
|
from urllib.parse import urlencode
|
|
@@ -7,29 +6,25 @@ from urllib.request import Request
|
|
|
7
6
|
|
|
8
7
|
from wagtail.embeds.exceptions import EmbedException, EmbedNotFoundException
|
|
9
8
|
|
|
10
|
-
from .
|
|
9
|
+
from .oembed import OEmbedFinder
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class AccessDeniedFacebookOEmbedException(EmbedException):
|
|
14
13
|
pass
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
https://developers.facebook.com/docs/plugins/oembed
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
facebook_video = {
|
|
16
|
+
FACEBOOK_PROVIDERS = [
|
|
17
|
+
# Videos
|
|
18
|
+
{
|
|
24
19
|
"endpoint": "https://graph.facebook.com/v11.0/oembed_video",
|
|
25
20
|
"urls": [
|
|
26
21
|
r"^https://(?:www\.)?facebook\.com/.+?/videos/.+$",
|
|
27
22
|
r"^https://(?:www\.)?facebook\.com/video\.php\?(?:v|id)=.+$",
|
|
28
23
|
r"^https://fb.watch/.+$",
|
|
29
24
|
],
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
},
|
|
26
|
+
# Posts
|
|
27
|
+
{
|
|
33
28
|
"endpoint": "https://graph.facebook.com/v11.0/oembed_post",
|
|
34
29
|
"urls": [
|
|
35
30
|
r"^https://(?:www\.)?facebook\.com/.+?/(?:posts|activity)/.+$",
|
|
@@ -42,7 +37,15 @@ class FacebookOEmbedFinder(EmbedFinder):
|
|
|
42
37
|
# Works for posts with a single photo
|
|
43
38
|
r"^https://(?:www\.)?facebook\.com/.+?/photos/.+$",
|
|
44
39
|
],
|
|
45
|
-
}
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FacebookOEmbedFinder(OEmbedFinder):
|
|
45
|
+
"""
|
|
46
|
+
An embed finder that supports the authenticated Facebook oEmbed Endpoint.
|
|
47
|
+
https://developers.facebook.com/docs/plugins/oembed
|
|
48
|
+
"""
|
|
46
49
|
|
|
47
50
|
def __init__(self, omitscript=False, app_id=None, app_secret=None):
|
|
48
51
|
# {settings.facebook_APP_ID}|{settings.facebook_APP_SECRET}
|
|
@@ -50,26 +53,7 @@ class FacebookOEmbedFinder(EmbedFinder):
|
|
|
50
53
|
self.app_secret = app_secret
|
|
51
54
|
self.omitscript = omitscript
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for provider in [self.facebook_video, self.facebook_post]:
|
|
56
|
-
patterns = []
|
|
57
|
-
|
|
58
|
-
endpoint = provider["endpoint"].replace("{format}", "json")
|
|
59
|
-
|
|
60
|
-
for url in provider["urls"]:
|
|
61
|
-
patterns.append(re.compile(url))
|
|
62
|
-
|
|
63
|
-
self._endpoints[endpoint] = patterns
|
|
64
|
-
|
|
65
|
-
def _get_endpoint(self, url):
|
|
66
|
-
for endpoint, patterns in self._endpoints.items():
|
|
67
|
-
for pattern in patterns:
|
|
68
|
-
if re.match(pattern, url):
|
|
69
|
-
return endpoint
|
|
70
|
-
|
|
71
|
-
def accept(self, url):
|
|
72
|
-
return self._get_endpoint(url) is not None
|
|
56
|
+
super().__init__(providers=FACEBOOK_PROVIDERS)
|
|
73
57
|
|
|
74
58
|
def find_embed(self, url, max_width=None, max_height=None):
|
|
75
59
|
# Find provider
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import re
|
|
3
2
|
from urllib import request as urllib_request
|
|
4
3
|
from urllib.error import HTTPError, URLError
|
|
5
4
|
from urllib.parse import urlencode
|
|
@@ -7,39 +6,43 @@ from urllib.request import Request
|
|
|
7
6
|
|
|
8
7
|
from wagtail.embeds.exceptions import EmbedException, EmbedNotFoundException
|
|
9
8
|
|
|
10
|
-
from .
|
|
9
|
+
from .oembed import OEmbedFinder
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class AccessDeniedInstagramOEmbedException(EmbedException):
|
|
14
13
|
pass
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
INSTAGRAM_PROVIDER = {
|
|
17
|
+
"endpoint": "https://graph.facebook.com/v11.0/instagram_oembed",
|
|
18
|
+
"urls": [
|
|
19
|
+
r"^https?://(?:www\.)?instagram\.com/p/.+$",
|
|
20
|
+
r"^https?://(?:www\.)?instagram\.com/tv/.+$",
|
|
21
|
+
r"^https?://(?:www\.)?instagram\.com/reel/.+$",
|
|
22
|
+
],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class InstagramOEmbedFinder(OEmbedFinder):
|
|
18
27
|
"""
|
|
19
28
|
An embed finder that supports the authenticated Instagram oEmbed Endpoint.
|
|
20
29
|
https://developers.facebook.com/docs/instagram/oembed
|
|
21
30
|
"""
|
|
22
31
|
|
|
23
|
-
INSTAGRAM_ENDPOINT = "https://graph.facebook.com/v11.0/instagram_oembed"
|
|
24
|
-
INSTAGRAM_URL_PATTERNS = [
|
|
25
|
-
r"^https?://(?:www\.)?instagram\.com/p/.+$",
|
|
26
|
-
r"^https?://(?:www\.)?instagram\.com/tv/.+$",
|
|
27
|
-
r"^https?://(?:www\.)?instagram\.com/reel/.+$",
|
|
28
|
-
]
|
|
29
|
-
|
|
30
32
|
def __init__(self, omitscript=False, app_id=None, app_secret=None):
|
|
31
33
|
# {settings.INSTAGRAM_APP_ID}|{settings.INSTAGRAM_APP_SECRET}
|
|
32
34
|
self.app_id = app_id
|
|
33
35
|
self.app_secret = app_secret
|
|
34
36
|
self.omitscript = omitscript
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
for pattern in self.INSTAGRAM_URL_PATTERNS:
|
|
38
|
-
if re.match(pattern, url):
|
|
39
|
-
return True
|
|
40
|
-
return False
|
|
38
|
+
super().__init__(providers=[INSTAGRAM_PROVIDER])
|
|
41
39
|
|
|
42
40
|
def find_embed(self, url, max_width=None, max_height=None):
|
|
41
|
+
# Find provider
|
|
42
|
+
endpoint = self._get_endpoint(url)
|
|
43
|
+
if endpoint is None:
|
|
44
|
+
raise EmbedNotFoundException
|
|
45
|
+
|
|
43
46
|
params = {"url": url, "format": "json"}
|
|
44
47
|
if max_width:
|
|
45
48
|
params["maxwidth"] = max_width
|
|
@@ -49,7 +52,7 @@ class InstagramOEmbedFinder(EmbedFinder):
|
|
|
49
52
|
params["omitscript"] = "true"
|
|
50
53
|
|
|
51
54
|
# Configure request
|
|
52
|
-
request = Request(
|
|
55
|
+
request = Request(endpoint + "?" + urlencode(params))
|
|
53
56
|
request.add_header("Authorization", f"Bearer {self.app_id}|{self.app_secret}")
|
|
54
57
|
|
|
55
58
|
# Perform request
|
|
@@ -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-07-19 16:26+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"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from django.core.signals import setting_changed
|
|
2
|
+
from django.dispatch import receiver
|
|
3
|
+
|
|
4
|
+
from .finders import get_finders
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@receiver(setting_changed)
|
|
8
|
+
def clear_embed_caches(*, setting: str, **kwargs: dict) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Clear the embed caches when settings change
|
|
11
|
+
"""
|
|
12
|
+
if setting == "WAGTAILEMBEDS_FINDERS":
|
|
13
|
+
get_finders.cache_clear()
|
|
@@ -652,7 +652,7 @@ class TestInstagramOEmbed(TestCase):
|
|
|
652
652
|
def test_instagram_oembed_return_values(self, urlopen):
|
|
653
653
|
urlopen.return_value = self.dummy_response
|
|
654
654
|
result = InstagramOEmbedFinder(app_id="123", app_secret="abc").find_embed(
|
|
655
|
-
"https://
|
|
655
|
+
"https://instagram.com/p/CHeRxmnDSYe/"
|
|
656
656
|
)
|
|
657
657
|
self.assertEqual(
|
|
658
658
|
result,
|
|
@@ -671,13 +671,13 @@ class TestInstagramOEmbed(TestCase):
|
|
|
671
671
|
request = urlopen.call_args[0][0]
|
|
672
672
|
self.assertEqual(
|
|
673
673
|
request.get_full_url(),
|
|
674
|
-
"https://graph.facebook.com/v11.0/instagram_oembed?url=https%3A%2F%
|
|
674
|
+
"https://graph.facebook.com/v11.0/instagram_oembed?url=https%3A%2F%2Finstagram.com%2Fp%2FCHeRxmnDSYe%2F&format=json",
|
|
675
675
|
)
|
|
676
676
|
self.assertEqual(request.get_header("Authorization"), "Bearer 123|abc")
|
|
677
677
|
|
|
678
678
|
def test_instagram_request_denied_401(self):
|
|
679
679
|
err = HTTPError(
|
|
680
|
-
"https://
|
|
680
|
+
"https://instagram.com/p/CHeRxmnDSYe/",
|
|
681
681
|
code=401,
|
|
682
682
|
msg="invalid credentials",
|
|
683
683
|
hdrs={},
|
|
@@ -688,12 +688,12 @@ class TestInstagramOEmbed(TestCase):
|
|
|
688
688
|
self.assertRaises(
|
|
689
689
|
AccessDeniedInstagramOEmbedException,
|
|
690
690
|
InstagramOEmbedFinder().find_embed,
|
|
691
|
-
"https://
|
|
691
|
+
"https://instagram.com/p/CHeRxmnDSYe/",
|
|
692
692
|
)
|
|
693
693
|
|
|
694
694
|
def test_instagram_request_not_found(self):
|
|
695
695
|
err = HTTPError(
|
|
696
|
-
"https://
|
|
696
|
+
"https://instagram.com/p/badrequest/",
|
|
697
697
|
code=404,
|
|
698
698
|
msg="Not Found",
|
|
699
699
|
hdrs={},
|
|
@@ -704,7 +704,7 @@ class TestInstagramOEmbed(TestCase):
|
|
|
704
704
|
self.assertRaises(
|
|
705
705
|
EmbedNotFoundException,
|
|
706
706
|
InstagramOEmbedFinder().find_embed,
|
|
707
|
-
"https://
|
|
707
|
+
"https://instagram.com/p/CHeRxmnDSYe/",
|
|
708
708
|
)
|
|
709
709
|
|
|
710
710
|
def test_instagram_failed_request(self):
|
|
@@ -713,7 +713,7 @@ class TestInstagramOEmbed(TestCase):
|
|
|
713
713
|
self.assertRaises(
|
|
714
714
|
EmbedNotFoundException,
|
|
715
715
|
InstagramOEmbedFinder().find_embed,
|
|
716
|
-
"https://
|
|
716
|
+
"https://instagram.com/p/CHeRxmnDSYe/",
|
|
717
717
|
)
|
|
718
718
|
|
|
719
719
|
|
wagtail/fields.py
CHANGED
|
@@ -5,8 +5,13 @@ from django.core.validators import MaxLengthValidator
|
|
|
5
5
|
from django.db import models
|
|
6
6
|
from django.db.models.fields.json import KeyTransform
|
|
7
7
|
from django.utils.encoding import force_str
|
|
8
|
+
from django.utils.functional import cached_property
|
|
8
9
|
|
|
9
10
|
from wagtail.blocks import Block, BlockField, StreamBlock, StreamValue
|
|
11
|
+
from wagtail.blocks.definition_lookup import (
|
|
12
|
+
BlockDefinitionLookup,
|
|
13
|
+
BlockDefinitionLookupBuilder,
|
|
14
|
+
)
|
|
10
15
|
from wagtail.rich_text import (
|
|
11
16
|
RichTextMaxLengthValidator,
|
|
12
17
|
extract_references_from_rich_text,
|
|
@@ -82,34 +87,68 @@ class Creator:
|
|
|
82
87
|
|
|
83
88
|
|
|
84
89
|
class StreamField(models.Field):
|
|
85
|
-
def __init__(self, block_types, use_json_field=True, **kwargs):
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
def __init__(self, block_types, use_json_field=True, block_lookup=None, **kwargs):
|
|
91
|
+
"""
|
|
92
|
+
Construct a StreamField.
|
|
93
|
+
|
|
94
|
+
:param block_types: Either a list of block types that are allowed in this StreamField
|
|
95
|
+
(as a list of tuples of block name and block instance) or a StreamBlock to use as
|
|
96
|
+
the top level block (as a block instance or class).
|
|
97
|
+
:param use_json_field: Ignored, but retained for compatibility with historical migrations.
|
|
98
|
+
:param block_lookup: Used in migrations to provide a more compact block definition -
|
|
99
|
+
see ``wagtail.blocks.definition_lookup.BlockDefinitionLookup``. If passed, ``block_types``
|
|
100
|
+
can contain integer indexes into this lookup table, in place of actual block instances.
|
|
101
|
+
"""
|
|
88
102
|
|
|
89
103
|
# extract kwargs that are to be passed on to the block, not handled by super
|
|
90
|
-
block_opts = {}
|
|
104
|
+
self.block_opts = {}
|
|
91
105
|
for arg in ["min_num", "max_num", "block_counts", "collapsed"]:
|
|
92
106
|
if arg in kwargs:
|
|
93
|
-
block_opts[arg] = kwargs.pop(arg)
|
|
107
|
+
self.block_opts[arg] = kwargs.pop(arg)
|
|
94
108
|
|
|
95
109
|
# for a top-level block, the 'blank' kwarg (defaulting to False) always overrides the
|
|
96
110
|
# block's own 'required' meta attribute, even if not passed explicitly; this ensures
|
|
97
111
|
# that the field and block have consistent definitions
|
|
98
|
-
block_opts["required"] = not kwargs.get("blank", False)
|
|
112
|
+
self.block_opts["required"] = not kwargs.get("blank", False)
|
|
113
|
+
|
|
114
|
+
# Store the `block_types` and `block_lookup` arguments to be handled in the `stream_block`
|
|
115
|
+
# property
|
|
116
|
+
self.block_types_arg = block_types
|
|
117
|
+
self.block_lookup = block_lookup
|
|
99
118
|
|
|
100
119
|
super().__init__(**kwargs)
|
|
101
120
|
|
|
102
|
-
|
|
121
|
+
@cached_property
|
|
122
|
+
def stream_block(self):
|
|
123
|
+
has_block_lookup = self.block_lookup is not None
|
|
124
|
+
if has_block_lookup:
|
|
125
|
+
lookup = BlockDefinitionLookup(self.block_lookup)
|
|
126
|
+
|
|
127
|
+
if isinstance(self.block_types_arg, Block):
|
|
103
128
|
# use the passed block as the top-level block
|
|
104
|
-
|
|
105
|
-
elif isinstance(
|
|
129
|
+
block = self.block_types_arg
|
|
130
|
+
elif isinstance(self.block_types_arg, int) and has_block_lookup:
|
|
131
|
+
# retrieve block from lookup table to use as the top-level block
|
|
132
|
+
block = lookup.get_block(self.block_types_arg)
|
|
133
|
+
elif isinstance(self.block_types_arg, type):
|
|
106
134
|
# block passed as a class - instantiate it
|
|
107
|
-
|
|
135
|
+
block = self.block_types_arg()
|
|
108
136
|
else:
|
|
109
|
-
# construct a top-level StreamBlock from the list of block types
|
|
110
|
-
|
|
137
|
+
# construct a top-level StreamBlock from the list of block types.
|
|
138
|
+
# If an integer is found in place of a block instance, and block_lookup is
|
|
139
|
+
# provided, it will be replaced with the corresponding block definition.
|
|
140
|
+
child_blocks = []
|
|
141
|
+
|
|
142
|
+
for name, child_block in self.block_types_arg:
|
|
143
|
+
if isinstance(child_block, int) and has_block_lookup:
|
|
144
|
+
child_blocks.append((name, lookup.get_block(child_block)))
|
|
145
|
+
else:
|
|
146
|
+
child_blocks.append((name, child_block))
|
|
147
|
+
|
|
148
|
+
block = StreamBlock(child_blocks)
|
|
111
149
|
|
|
112
|
-
|
|
150
|
+
block.set_meta_options(self.block_opts)
|
|
151
|
+
return block
|
|
113
152
|
|
|
114
153
|
@property
|
|
115
154
|
def json_field(self):
|
|
@@ -126,8 +165,13 @@ class StreamField(models.Field):
|
|
|
126
165
|
|
|
127
166
|
def deconstruct(self):
|
|
128
167
|
name, path, _, kwargs = super().deconstruct()
|
|
129
|
-
|
|
168
|
+
lookup = BlockDefinitionLookupBuilder()
|
|
169
|
+
block_types = [
|
|
170
|
+
(name, lookup.add_block(block))
|
|
171
|
+
for name, block in self.stream_block.child_blocks.items()
|
|
172
|
+
]
|
|
130
173
|
args = [block_types]
|
|
174
|
+
kwargs["block_lookup"] = lookup.get_lookup_as_dict()
|
|
131
175
|
return name, path, args, kwargs
|
|
132
176
|
|
|
133
177
|
def to_python(self, value):
|
wagtail/images/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ def get_image_model():
|
|
|
15
15
|
"""
|
|
16
16
|
Get the image model from the ``WAGTAILIMAGES_IMAGE_MODEL`` setting.
|
|
17
17
|
Useful for developers making Wagtail plugins that need the image model.
|
|
18
|
-
Defaults to the standard
|
|
18
|
+
Defaults to the standard ``wagtail.images.models.Image`` model
|
|
19
19
|
if no custom model is defined.
|
|
20
20
|
"""
|
|
21
21
|
from django.apps import apps
|