wagtail 7.1.1__py3-none-any.whl → 7.1.3__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/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/templates/wagtailadmin/generic/form.html +3 -1
- wagtail/admin/templates/wagtailadmin/userbar/base.html +6 -3
- wagtail/admin/templates/wagtailadmin/userbar/item_admin.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_add.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_edit.html +2 -2
- wagtail/admin/templates/wagtailadmin/userbar/item_page_explore.html +2 -2
- wagtail/admin/templatetags/wagtailadmin_tags.py +27 -0
- wagtail/admin/tests/pages/test_preview.py +111 -0
- wagtail/admin/tests/test_userbar.py +75 -35
- wagtail/admin/tests/test_views_generic.py +34 -0
- wagtail/admin/userbar.py +6 -1
- wagtail/admin/views/generic/preview.py +8 -1
- wagtail/admin/views/pages/preview.py +10 -1
- wagtail/blocks/struct_block.py +2 -1
- wagtail/contrib/settings/tests/shared/test_preview.py +29 -0
- wagtail/contrib/settings/views.py +8 -2
- wagtail/documents/tests/test_admin_views.py +25 -0
- wagtail/documents/views/documents.py +3 -1
- wagtail/images/tests/test_admin_views.py +26 -0
- wagtail/images/views/images.py +10 -2
- wagtail/snippets/tests/test_preview.py +77 -11
- wagtail/test/testapp/urls.py +1 -0
- wagtail/test/testapp/views.py +15 -1
- wagtail/tests/test_blocks.py +15 -0
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/METADATA +1 -1
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/RECORD +33 -33
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/WHEEL +1 -1
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/entry_points.txt +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/licenses/LICENSE +0 -0
- {wagtail-7.1.1.dist-info → wagtail-7.1.3.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
{% if breadcrumbs_items %}
|
|
7
7
|
<div class="nice-padding w-mt-8">
|
|
8
8
|
<h2 class="w-relative w-h1" id="header-title">
|
|
9
|
-
{%
|
|
9
|
+
{% if header_icon %}
|
|
10
|
+
{% icon classname="w-absolute w-top-1 -w-left-11 w-max-w-[1em] w-max-h-[1em]" name=header_icon %}
|
|
11
|
+
{% endif %}
|
|
10
12
|
{{ page_subtitle|default:page_title }}
|
|
11
13
|
</h2>
|
|
12
14
|
</div>
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
<aside {% if request.in_preview_panel %}hidden{% endif %}>
|
|
6
6
|
<div class="w-userbar w-userbar--{{ position|default:'bottom-right' }} {% admin_theme_classname %}" data-wagtail-userbar data-wagtail-userbar-origin="{{ origin|default:"" }}" part="userbar">
|
|
7
7
|
{% block css %}
|
|
8
|
-
|
|
8
|
+
{% versioned_static 'wagtailadmin/css/core.css' as core_css_url %}
|
|
9
|
+
<link rel="stylesheet" href="{% build_absolute_url core_css_url %}">
|
|
9
10
|
{# For headless userbar: the contents of the hook also need absolute URLs #}
|
|
10
11
|
{% hook_output 'insert_global_admin_css' %}
|
|
11
12
|
{% endblock %}
|
|
@@ -44,7 +45,9 @@
|
|
|
44
45
|
</template>
|
|
45
46
|
<wagtail-userbar></wagtail-userbar>
|
|
46
47
|
{% block js %}
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
{% versioned_static 'wagtailadmin/js/vendor.js' as vendor_js_url %}
|
|
49
|
+
{% versioned_static 'wagtailadmin/js/userbar.js' as userbar_js_url %}
|
|
50
|
+
<script src="{% build_absolute_url vendor_js_url %}"></script>
|
|
51
|
+
<script src="{% build_absolute_url userbar_js_url %}"></script>
|
|
49
52
|
{% endblock %}
|
|
50
53
|
<!-- end Wagtail user bar embed code -->
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
{% load i18n wagtailadmin_tags %}
|
|
3
3
|
|
|
4
4
|
{% block item_content %}
|
|
5
|
-
{%
|
|
6
|
-
<a href="{
|
|
5
|
+
{% url 'wagtailadmin_home' as admin_home_url %}
|
|
6
|
+
<a href="{% build_absolute_url admin_home_url %}" target="_parent" role="menuitem">
|
|
7
7
|
{% icon name="key" classname="w-action-icon" %}
|
|
8
8
|
{% trans 'Go to Wagtail admin' %}
|
|
9
9
|
</a>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
{% load i18n wagtailadmin_tags %}
|
|
3
3
|
|
|
4
4
|
{% block item_content %}
|
|
5
|
-
{%
|
|
6
|
-
<a href="{
|
|
5
|
+
{% url 'wagtailadmin_pages:add_subpage' self.page.id as add_url %}
|
|
6
|
+
<a href="{% build_absolute_url add_url %}" target="_parent" role="menuitem">
|
|
7
7
|
{% icon name="plus" classname="w-action-icon" %}
|
|
8
8
|
{% trans 'Add a child page' %}
|
|
9
9
|
</a>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
{% load i18n wagtailadmin_tags %}
|
|
3
3
|
|
|
4
4
|
{% block item_content %}
|
|
5
|
-
{%
|
|
6
|
-
<a href="{
|
|
5
|
+
{% url 'wagtailadmin_pages:edit' self.page.id as edit_url %}
|
|
6
|
+
<a href="{% build_absolute_url edit_url %}" target="_parent" role="menuitem">
|
|
7
7
|
{% icon name="edit" classname="w-action-icon" %}
|
|
8
8
|
{% trans 'Edit this page' %}
|
|
9
9
|
</a>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
{% load i18n wagtailadmin_tags %}
|
|
3
3
|
|
|
4
4
|
{% block item_content %}
|
|
5
|
-
{%
|
|
6
|
-
<a href="{
|
|
5
|
+
{% url 'wagtailadmin_explore' self.parent_page.id as explore_url %}
|
|
6
|
+
<a href="{% build_absolute_url explore_url %}" target="_parent" role="menuitem">
|
|
7
7
|
{% icon name="folder-open-inverse" classname="w-action-icon" %}
|
|
8
8
|
{% trans 'Show in Explorer' %}
|
|
9
9
|
</a>
|
|
@@ -206,6 +206,33 @@ def admin_url_name(obj, action):
|
|
|
206
206
|
return obj.snippet_viewset.get_url_name(action)
|
|
207
207
|
|
|
208
208
|
|
|
209
|
+
@register.simple_tag(takes_context=True)
|
|
210
|
+
def build_absolute_url(context, url):
|
|
211
|
+
"""
|
|
212
|
+
Usage: {% build_absolute_url url %}
|
|
213
|
+
Returns the absolute URL of the given URL based on the request's host.
|
|
214
|
+
If the request doesn't exist in the context, falls back to
|
|
215
|
+
WAGTAILADMIN_BASE_URL as the base URL.
|
|
216
|
+
If the given URL is already absolute, or the request is a dummy preview
|
|
217
|
+
request, returns it unchanged.
|
|
218
|
+
"""
|
|
219
|
+
request = context.get("request")
|
|
220
|
+
# If request is not found in the context, e.g. in notification emails,
|
|
221
|
+
# fall back to WAGTAILADMIN_BASE_URL.
|
|
222
|
+
if not request:
|
|
223
|
+
return urljoin(get_admin_base_url(), url)
|
|
224
|
+
# With a dummy preview request, the host has been overwritten to be the page
|
|
225
|
+
# Site's host, which may not have been configured correctly. We don't want
|
|
226
|
+
# to fall back to WAGTAILADMIN_BASE_URL either, as that may be different
|
|
227
|
+
# from the original request's host in multi-site instances and may result in
|
|
228
|
+
# users having to log in again. So we just return the URL unchanged.
|
|
229
|
+
if getattr(request, "is_dummy", False):
|
|
230
|
+
return url
|
|
231
|
+
# Rewrite relative URLs to absolute URLs based on the request's host, but
|
|
232
|
+
# leave absolute URLs unchanged.
|
|
233
|
+
return request.build_absolute_uri(url)
|
|
234
|
+
|
|
235
|
+
|
|
209
236
|
@register.simple_tag
|
|
210
237
|
def latest_str(obj):
|
|
211
238
|
"""
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
from functools import wraps
|
|
3
3
|
|
|
4
|
+
from django.contrib.auth.models import Permission
|
|
4
5
|
from django.test import TestCase, override_settings
|
|
5
6
|
from django.urls import reverse
|
|
6
7
|
from django.utils import timezone
|
|
@@ -358,6 +359,47 @@ class TestPreview(WagtailTestUtils, TestCase):
|
|
|
358
359
|
self.assertTemplateUsed(response, "tests/event_page.html")
|
|
359
360
|
self.assertContains(response, "Placeholder title")
|
|
360
361
|
|
|
362
|
+
def test_preview_on_create_without_permissions(self):
|
|
363
|
+
# Remove privileges from user
|
|
364
|
+
self.user.is_superuser = False
|
|
365
|
+
self.user.user_permissions.add(
|
|
366
|
+
Permission.objects.get(
|
|
367
|
+
content_type__app_label="wagtailadmin", codename="access_admin"
|
|
368
|
+
)
|
|
369
|
+
)
|
|
370
|
+
self.user.save()
|
|
371
|
+
|
|
372
|
+
preview_url = reverse(
|
|
373
|
+
"wagtailadmin_pages:preview_on_add",
|
|
374
|
+
args=("tests", "eventpage", self.home_page.id),
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
response = self.client.post(
|
|
378
|
+
preview_url,
|
|
379
|
+
self.post_data,
|
|
380
|
+
)
|
|
381
|
+
self.assertEqual(response.status_code, 302)
|
|
382
|
+
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
383
|
+
|
|
384
|
+
def test_preview_on_create_get_without_permissions(self):
|
|
385
|
+
# Remove privileges from user
|
|
386
|
+
self.user.is_superuser = False
|
|
387
|
+
self.user.user_permissions.add(
|
|
388
|
+
Permission.objects.get(
|
|
389
|
+
content_type__app_label="wagtailadmin", codename="access_admin"
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
self.user.save()
|
|
393
|
+
|
|
394
|
+
preview_url = reverse(
|
|
395
|
+
"wagtailadmin_pages:preview_on_add",
|
|
396
|
+
args=("tests", "eventpage", self.home_page.id),
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
response = self.client.get(preview_url)
|
|
400
|
+
self.assertEqual(response.status_code, 302)
|
|
401
|
+
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
402
|
+
|
|
361
403
|
def test_preview_on_edit_with_m2m_field(self):
|
|
362
404
|
preview_url = reverse(
|
|
363
405
|
"wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
|
|
@@ -414,6 +456,36 @@ class TestPreview(WagtailTestUtils, TestCase):
|
|
|
414
456
|
self.assertContains(response, "<li>Parties</li>")
|
|
415
457
|
self.assertContains(response, "<li>Holidays</li>")
|
|
416
458
|
|
|
459
|
+
soup = self.get_soup(response.content)
|
|
460
|
+
userbar = soup.select_one("wagtail-userbar")
|
|
461
|
+
self.assertIsNotNone(userbar)
|
|
462
|
+
template = soup.select_one("#wagtail-userbar-template")
|
|
463
|
+
self.assertIsNotNone(template)
|
|
464
|
+
|
|
465
|
+
# Previews use a dummy request object, so the userbar should use
|
|
466
|
+
# relative URLs to avoid using the wrong host.
|
|
467
|
+
admin_url = reverse("wagtailadmin_home")
|
|
468
|
+
admin_link = template.select_one(f'a[href$="{admin_url}"]')
|
|
469
|
+
self.assertIsNotNone(admin_link)
|
|
470
|
+
self.assertEqual(admin_link["href"], admin_url)
|
|
471
|
+
|
|
472
|
+
css_links = soup.select("link[rel='stylesheet']")
|
|
473
|
+
self.assertEqual(
|
|
474
|
+
[link.get("href") for link in css_links],
|
|
475
|
+
[
|
|
476
|
+
versioned_static("wagtailadmin/css/core.css"),
|
|
477
|
+
"/path/to/my/custom.css",
|
|
478
|
+
],
|
|
479
|
+
)
|
|
480
|
+
scripts = soup.select("script[src]")
|
|
481
|
+
self.assertEqual(
|
|
482
|
+
[script.get("src") for script in scripts],
|
|
483
|
+
[
|
|
484
|
+
versioned_static("wagtailadmin/js/vendor.js"),
|
|
485
|
+
versioned_static("wagtailadmin/js/userbar.js"),
|
|
486
|
+
],
|
|
487
|
+
)
|
|
488
|
+
|
|
417
489
|
def test_preview_on_edit_with_valid_then_invalid_data(self):
|
|
418
490
|
preview_url = reverse(
|
|
419
491
|
"wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
|
|
@@ -557,6 +629,45 @@ class TestPreview(WagtailTestUtils, TestCase):
|
|
|
557
629
|
response = self.client.get(preview_url)
|
|
558
630
|
self.assertEqual(response.status_code, 200)
|
|
559
631
|
|
|
632
|
+
def test_preview_on_edit_without_permissions(self):
|
|
633
|
+
# Remove privileges from user
|
|
634
|
+
self.user.is_superuser = False
|
|
635
|
+
self.user.user_permissions.add(
|
|
636
|
+
Permission.objects.get(
|
|
637
|
+
content_type__app_label="wagtailadmin", codename="access_admin"
|
|
638
|
+
)
|
|
639
|
+
)
|
|
640
|
+
self.user.save()
|
|
641
|
+
|
|
642
|
+
preview_url = reverse(
|
|
643
|
+
"wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
response = self.client.post(
|
|
647
|
+
preview_url,
|
|
648
|
+
self.post_data,
|
|
649
|
+
)
|
|
650
|
+
self.assertEqual(response.status_code, 302)
|
|
651
|
+
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
652
|
+
|
|
653
|
+
def test_preview_on_edit_get_without_permissions(self):
|
|
654
|
+
# Remove privileges from user
|
|
655
|
+
self.user.is_superuser = False
|
|
656
|
+
self.user.user_permissions.add(
|
|
657
|
+
Permission.objects.get(
|
|
658
|
+
content_type__app_label="wagtailadmin", codename="access_admin"
|
|
659
|
+
)
|
|
660
|
+
)
|
|
661
|
+
self.user.save()
|
|
662
|
+
|
|
663
|
+
preview_url = reverse(
|
|
664
|
+
"wagtailadmin_pages:preview_on_edit", args=(self.event_page.id,)
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
response = self.client.get(preview_url)
|
|
668
|
+
self.assertEqual(response.status_code, 302)
|
|
669
|
+
self.assertRedirects(response, reverse("wagtailadmin_home"))
|
|
670
|
+
|
|
560
671
|
def test_preview_on_create_clear_preview_data(self):
|
|
561
672
|
preview_session_key = "wagtail-preview-tests-eventpage-{}".format(
|
|
562
673
|
self.home_page.id
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
|
-
from django.conf import settings
|
|
4
3
|
from django.contrib.auth.models import AnonymousUser, Permission
|
|
5
4
|
from django.template import Context, Template
|
|
6
5
|
from django.test import TestCase, override_settings
|
|
@@ -9,7 +8,7 @@ from django.utils import translation
|
|
|
9
8
|
from django.utils.translation import gettext
|
|
10
9
|
|
|
11
10
|
from wagtail import hooks
|
|
12
|
-
from wagtail.admin.
|
|
11
|
+
from wagtail.admin.staticfiles import versioned_static
|
|
13
12
|
from wagtail.admin.userbar import AccessibilityItem, Userbar
|
|
14
13
|
from wagtail.coreutils import get_dummy_request
|
|
15
14
|
from wagtail.models import PAGE_TEMPLATE_VAR, Locale, Page, Site
|
|
@@ -67,7 +66,7 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
67
66
|
# Wagtail admin core CSS should be linked with absolute URL to
|
|
68
67
|
# ensure it works when loaded from a different domain
|
|
69
68
|
# (e.g. headless frontend)
|
|
70
|
-
|
|
69
|
+
f"http://localhost{versioned_static('wagtailadmin/css/core.css')}",
|
|
71
70
|
# Custom CSS must be changed appropriately if necessary
|
|
72
71
|
"/path/to/my/custom.css",
|
|
73
72
|
],
|
|
@@ -80,8 +79,8 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
80
79
|
# Wagtail vendor and userbar JS should be linked with absolute
|
|
81
80
|
# URL to ensure it works when loaded from a different domain
|
|
82
81
|
# (e.g. headless frontend)
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
f"http://localhost{versioned_static('wagtailadmin/js/vendor.js')}",
|
|
83
|
+
f"http://localhost{versioned_static('wagtailadmin/js/userbar.js')}",
|
|
85
84
|
],
|
|
86
85
|
)
|
|
87
86
|
|
|
@@ -136,9 +135,7 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
136
135
|
# Should render the "Go to Wagtail admin" link using an absolute URL
|
|
137
136
|
soup = self.get_soup(content)
|
|
138
137
|
admin_url = reverse("wagtailadmin_home")
|
|
139
|
-
admin_link = soup.select_one(
|
|
140
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{admin_url}']"
|
|
141
|
-
)
|
|
138
|
+
admin_link = soup.select_one(f"a[href='http://localhost{admin_url}']")
|
|
142
139
|
self.assertIsNotNone(admin_link)
|
|
143
140
|
self.assertEqual(admin_link.text.strip(), "Go to Wagtail admin")
|
|
144
141
|
|
|
@@ -156,16 +153,12 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
156
153
|
soup = self.get_soup(content)
|
|
157
154
|
|
|
158
155
|
edit_url = reverse("wagtailadmin_pages:edit", args=(self.homepage.id,))
|
|
159
|
-
edit_link = soup.select_one(
|
|
160
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{edit_url}']"
|
|
161
|
-
)
|
|
156
|
+
edit_link = soup.select_one(f"a[href='http://localhost{edit_url}']")
|
|
162
157
|
self.assertIsNotNone(edit_link)
|
|
163
158
|
self.assertEqual(edit_link.text.strip(), "Edit this page")
|
|
164
159
|
|
|
165
160
|
explore_url = reverse("wagtailadmin_explore", args=(self.parent_page.id,))
|
|
166
|
-
explore_link = soup.select_one(
|
|
167
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{explore_url}']"
|
|
168
|
-
)
|
|
161
|
+
explore_link = soup.select_one(f"a[href='http://localhost{explore_url}']")
|
|
169
162
|
self.assertIsNotNone(explore_link)
|
|
170
163
|
self.assertEqual(explore_link.text.strip(), "Show in Explorer")
|
|
171
164
|
|
|
@@ -185,16 +178,12 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
185
178
|
soup = self.get_soup(content)
|
|
186
179
|
|
|
187
180
|
edit_url = reverse("wagtailadmin_pages:edit", args=(self.homepage.id,))
|
|
188
|
-
edit_link = soup.select_one(
|
|
189
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{edit_url}']"
|
|
190
|
-
)
|
|
181
|
+
edit_link = soup.select_one(f"a[href='http://localhost{edit_url}']")
|
|
191
182
|
self.assertIsNotNone(edit_link)
|
|
192
183
|
self.assertEqual(edit_link.text.strip(), "Edit this page")
|
|
193
184
|
|
|
194
185
|
explore_url = reverse("wagtailadmin_explore", args=(self.parent_page.id,))
|
|
195
|
-
explore_link = soup.select_one(
|
|
196
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{explore_url}']"
|
|
197
|
-
)
|
|
186
|
+
explore_link = soup.select_one(f"a[href='http://localhost{explore_url}']")
|
|
198
187
|
self.assertIsNotNone(explore_link)
|
|
199
188
|
self.assertEqual(explore_link.text.strip(), "Show in Explorer")
|
|
200
189
|
|
|
@@ -221,9 +210,7 @@ class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
|
221
210
|
# The explore link should still be visible
|
|
222
211
|
soup = self.get_soup(content)
|
|
223
212
|
explore_url = reverse("wagtailadmin_explore", args=(self.parent_page.id,))
|
|
224
|
-
explore_link = soup.select_one(
|
|
225
|
-
f"a[href='{settings.WAGTAILADMIN_BASE_URL}{explore_url}']"
|
|
226
|
-
)
|
|
213
|
+
explore_link = soup.select_one(f"a[href='http://localhost{explore_url}']")
|
|
227
214
|
self.assertIsNotNone(explore_link)
|
|
228
215
|
self.assertEqual(explore_link.text.strip(), "Show in Explorer")
|
|
229
216
|
|
|
@@ -718,7 +705,7 @@ class TestUserbarAddLink(WagtailTestUtils, TestCase):
|
|
|
718
705
|
self.assertEqual(response.status_code, 200)
|
|
719
706
|
|
|
720
707
|
# page allows subpages, so the 'add page' button should show
|
|
721
|
-
expected_url =
|
|
708
|
+
expected_url = self.request.build_absolute_uri(
|
|
722
709
|
reverse("wagtailadmin_pages:add_subpage", args=(self.event_index.id,))
|
|
723
710
|
)
|
|
724
711
|
needle = f"""
|
|
@@ -762,7 +749,7 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
762
749
|
items = soup.select("li")
|
|
763
750
|
self.assertEqual(len(items), 2)
|
|
764
751
|
|
|
765
|
-
admin_url = f"{
|
|
752
|
+
admin_url = f"http://localhost{reverse('wagtailadmin_home')}"
|
|
766
753
|
admin_item = items[0]
|
|
767
754
|
admin_link = admin_item.select_one("a")
|
|
768
755
|
self.assertIsNotNone(admin_link)
|
|
@@ -780,11 +767,18 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
780
767
|
def test_render_no_request(self):
|
|
781
768
|
rendered = Userbar().render_html({})
|
|
782
769
|
soup = self.get_soup(rendered)
|
|
770
|
+
# Without a request provided, URLs should fall back to the
|
|
771
|
+
# WAGTAILADMIN_BASE_URL setting
|
|
772
|
+
base_url = "http://testserver"
|
|
773
|
+
|
|
774
|
+
userbar = soup.select_one("[data-wagtail-userbar]")
|
|
775
|
+
self.assertIsNotNone(userbar)
|
|
776
|
+
self.assertEqual(userbar.get("data-wagtail-userbar-origin"), base_url)
|
|
783
777
|
|
|
784
778
|
items = soup.select("li")
|
|
785
779
|
self.assertEqual(len(items), 2)
|
|
786
780
|
|
|
787
|
-
admin_url = f"{
|
|
781
|
+
admin_url = f"{base_url}{reverse('wagtailadmin_home')}"
|
|
788
782
|
admin_item = items[0]
|
|
789
783
|
admin_link = admin_item.select_one("a")
|
|
790
784
|
self.assertIsNotNone(admin_link)
|
|
@@ -799,21 +793,44 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
799
793
|
"Issues found | Accessibility",
|
|
800
794
|
)
|
|
801
795
|
|
|
796
|
+
css_links = soup.select("link[rel='stylesheet']")
|
|
797
|
+
self.assertEqual(
|
|
798
|
+
[link.get("href") for link in css_links],
|
|
799
|
+
[
|
|
800
|
+
# Wagtail admin core CSS should be linked with absolute URL to
|
|
801
|
+
# ensure it works when loaded from a different domain
|
|
802
|
+
# (e.g. headless frontend)
|
|
803
|
+
f"{base_url}{versioned_static('wagtailadmin/css/core.css')}",
|
|
804
|
+
# Custom CSS must be changed appropriately if necessary
|
|
805
|
+
"/path/to/my/custom.css",
|
|
806
|
+
],
|
|
807
|
+
)
|
|
808
|
+
|
|
809
|
+
scripts = soup.select("script[src]")
|
|
810
|
+
self.assertEqual(
|
|
811
|
+
[script.get("src") for script in scripts],
|
|
812
|
+
[
|
|
813
|
+
# Wagtail vendor and userbar JS should be linked with absolute
|
|
814
|
+
# URL to ensure it works when loaded from a different domain
|
|
815
|
+
# (e.g. headless frontend)
|
|
816
|
+
f"{base_url}{versioned_static('wagtailadmin/js/vendor.js')}",
|
|
817
|
+
f"{base_url}{versioned_static('wagtailadmin/js/userbar.js')}",
|
|
818
|
+
],
|
|
819
|
+
)
|
|
820
|
+
|
|
802
821
|
def test_render_minimal(self):
|
|
803
822
|
rendered = Userbar().render_html({"request": self.request})
|
|
804
823
|
soup = self.get_soup(rendered)
|
|
805
824
|
|
|
806
825
|
userbar = soup.select_one("[data-wagtail-userbar]")
|
|
807
826
|
self.assertIsNotNone(userbar)
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
settings.WAGTAILADMIN_BASE_URL,
|
|
811
|
-
)
|
|
827
|
+
# The origin should be based on the request's scheme and host information
|
|
828
|
+
self.assertEqual(userbar.get("data-wagtail-userbar-origin"), "http://localhost")
|
|
812
829
|
|
|
813
830
|
items = soup.select("li")
|
|
814
831
|
self.assertEqual(len(items), 2)
|
|
815
832
|
|
|
816
|
-
admin_url = f"{
|
|
833
|
+
admin_url = f"http://localhost{reverse('wagtailadmin_home')}"
|
|
817
834
|
admin_item = items[0]
|
|
818
835
|
admin_link = admin_item.select_one("a")
|
|
819
836
|
self.assertIsNotNone(admin_link)
|
|
@@ -844,7 +861,7 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
844
861
|
self.assertEqual(len(links), 4)
|
|
845
862
|
self.assertEqual(
|
|
846
863
|
[link.get("href") for link in links],
|
|
847
|
-
[f"{
|
|
864
|
+
[f"http://localhost{url}" for url in expected_urls],
|
|
848
865
|
)
|
|
849
866
|
|
|
850
867
|
accessibility_button = soup.select_one("li button")
|
|
@@ -855,8 +872,8 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
855
872
|
)
|
|
856
873
|
|
|
857
874
|
@override_settings(WAGTAILADMIN_BASE_URL=None)
|
|
858
|
-
def
|
|
859
|
-
rendered = Userbar().render_html({
|
|
875
|
+
def test_render_without_request_and_admin_base_url_setting(self):
|
|
876
|
+
rendered = Userbar().render_html({})
|
|
860
877
|
soup = self.get_soup(rendered)
|
|
861
878
|
|
|
862
879
|
userbar = soup.select_one("[data-wagtail-userbar]")
|
|
@@ -868,7 +885,8 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
868
885
|
items = soup.select("li")
|
|
869
886
|
self.assertEqual(len(items), 2)
|
|
870
887
|
|
|
871
|
-
# Becomes the root-relative URL since
|
|
888
|
+
# Becomes the root-relative URL since no request is provided
|
|
889
|
+
# and WAGTAILADMIN_BASE_URL is None
|
|
872
890
|
admin_url = reverse("wagtailadmin_home")
|
|
873
891
|
admin_item = items[0]
|
|
874
892
|
admin_link = admin_item.select_one("a")
|
|
@@ -883,3 +901,25 @@ class TestUserbarComponent(WagtailTestUtils, TestCase):
|
|
|
883
901
|
button.get_text(separator=" | ", strip=True).strip(),
|
|
884
902
|
"Issues found | Accessibility",
|
|
885
903
|
)
|
|
904
|
+
|
|
905
|
+
css_links = soup.select("link[rel='stylesheet']")
|
|
906
|
+
self.assertEqual(
|
|
907
|
+
[link.get("href") for link in css_links],
|
|
908
|
+
[
|
|
909
|
+
# Cannot build absolute URL without a request and
|
|
910
|
+
# WAGTAILADMIN_BASE_URL, so should be root-relative
|
|
911
|
+
versioned_static("wagtailadmin/css/core.css"),
|
|
912
|
+
"/path/to/my/custom.css",
|
|
913
|
+
],
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
scripts = soup.select("script[src]")
|
|
917
|
+
self.assertEqual(
|
|
918
|
+
[script.get("src") for script in scripts],
|
|
919
|
+
[
|
|
920
|
+
# Cannot build absolute URL without a request and
|
|
921
|
+
# WAGTAILADMIN_BASE_URL, so should be root-relative
|
|
922
|
+
versioned_static("wagtailadmin/js/vendor.js"),
|
|
923
|
+
versioned_static("wagtailadmin/js/userbar.js"),
|
|
924
|
+
],
|
|
925
|
+
)
|
|
@@ -2,6 +2,7 @@ from django.contrib.admin.utils import quote
|
|
|
2
2
|
from django.test import TestCase
|
|
3
3
|
from django.urls import reverse
|
|
4
4
|
|
|
5
|
+
from wagtail.test.testapp.models import ModelWithStringTypePrimaryKey
|
|
5
6
|
from wagtail.test.utils import WagtailTestUtils
|
|
6
7
|
|
|
7
8
|
|
|
@@ -37,6 +38,39 @@ class TestGenericIndexViewWithoutModel(WagtailTestUtils, TestCase):
|
|
|
37
38
|
self.assertEqual(response_object_count, 4)
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
class TestGenericCreateView(WagtailTestUtils, TestCase):
|
|
42
|
+
fixtures = ["test.json"]
|
|
43
|
+
|
|
44
|
+
def get(self, params={}):
|
|
45
|
+
return self.client.get(reverse("testapp_generic_create"), params)
|
|
46
|
+
|
|
47
|
+
def test_get_create_view(self):
|
|
48
|
+
response = self.get()
|
|
49
|
+
self.assertEqual(response.status_code, 200)
|
|
50
|
+
soup = self.get_soup(response.content)
|
|
51
|
+
h2 = soup.select_one("main h2")
|
|
52
|
+
self.assertIsNotNone(h2)
|
|
53
|
+
self.assertEqual(h2.text.strip(), "Model with string type primary key")
|
|
54
|
+
form = soup.select_one("main form")
|
|
55
|
+
self.assertIsNotNone(form)
|
|
56
|
+
id_input = form.select_one("input[name='custom_id']")
|
|
57
|
+
self.assertIsNotNone(id_input)
|
|
58
|
+
self.assertEqual(id_input.get("type"), "text")
|
|
59
|
+
content_input = form.select_one("input[name='content']")
|
|
60
|
+
self.assertIsNotNone(content_input)
|
|
61
|
+
|
|
62
|
+
def test_post_create_view(self):
|
|
63
|
+
post_data = {
|
|
64
|
+
"custom_id": "string-pk-3",
|
|
65
|
+
"content": "third modelwithstringtypeprimarykey model",
|
|
66
|
+
}
|
|
67
|
+
response = self.client.post(reverse("testapp_generic_create"), post_data)
|
|
68
|
+
self.assertEqual(response.status_code, 302) # Redirect to index view
|
|
69
|
+
self.assertTrue(
|
|
70
|
+
ModelWithStringTypePrimaryKey.objects.filter(pk="string-pk-3").exists()
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
40
74
|
class TestGenericEditView(WagtailTestUtils, TestCase):
|
|
41
75
|
fixtures = ["test.json"]
|
|
42
76
|
|
wagtail/admin/userbar.py
CHANGED
|
@@ -364,10 +364,15 @@ class Userbar(Component):
|
|
|
364
364
|
# Remove any unrendered items
|
|
365
365
|
rendered_items = [item for item in rendered_items if item]
|
|
366
366
|
|
|
367
|
+
if request:
|
|
368
|
+
origin = f"{request.scheme}://{request.get_host()}"
|
|
369
|
+
else:
|
|
370
|
+
origin = get_admin_base_url() or ""
|
|
371
|
+
|
|
367
372
|
# Render the userbar items
|
|
368
373
|
return {
|
|
369
374
|
"request": request,
|
|
370
|
-
"origin":
|
|
375
|
+
"origin": origin,
|
|
371
376
|
"items": rendered_items,
|
|
372
377
|
"position": self.position,
|
|
373
378
|
"page": self.object,
|
|
@@ -17,13 +17,16 @@ from wagtail.blocks.base import Block
|
|
|
17
17
|
from wagtail.models import PreviewableMixin, RevisionMixin
|
|
18
18
|
from wagtail.utils.decorators import xframe_options_sameorigin_override
|
|
19
19
|
|
|
20
|
+
from .permissions import PermissionCheckedMixin
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
class PreviewOnEdit(PermissionCheckedMixin, View):
|
|
22
24
|
model = None
|
|
23
25
|
form_class = None
|
|
24
26
|
http_method_names = ("post", "get", "delete")
|
|
25
27
|
preview_expiration_timeout = 60 * 60 * 24 # seconds
|
|
26
28
|
session_key_prefix = "wagtail-preview-"
|
|
29
|
+
permission_required = "change"
|
|
27
30
|
|
|
28
31
|
def setup(self, request, *args, **kwargs):
|
|
29
32
|
super().setup(request, *args, **kwargs)
|
|
@@ -54,6 +57,8 @@ class PreviewOnEdit(View):
|
|
|
54
57
|
|
|
55
58
|
def get_object(self):
|
|
56
59
|
obj = get_object_or_404(self.model, pk=unquote(str(self.kwargs["pk"])))
|
|
60
|
+
if not self.user_has_permission_for_instance(self.permission_required, obj):
|
|
61
|
+
raise PermissionDenied
|
|
57
62
|
if isinstance(obj, RevisionMixin):
|
|
58
63
|
obj = obj.get_latest_revision_as_object()
|
|
59
64
|
return obj
|
|
@@ -136,6 +141,8 @@ class PreviewOnEdit(View):
|
|
|
136
141
|
|
|
137
142
|
|
|
138
143
|
class PreviewOnCreate(PreviewOnEdit):
|
|
144
|
+
permission_required = "add"
|
|
145
|
+
|
|
139
146
|
@property
|
|
140
147
|
def session_key(self):
|
|
141
148
|
app_label = self.model._meta.app_label
|
|
@@ -30,9 +30,13 @@ class PreviewOnEdit(GenericPreviewOnEdit):
|
|
|
30
30
|
return "{}{}".format(self.session_key_prefix, self.kwargs["page_id"])
|
|
31
31
|
|
|
32
32
|
def get_object(self):
|
|
33
|
-
|
|
33
|
+
page = get_object_or_404(
|
|
34
34
|
Page, id=self.kwargs["page_id"]
|
|
35
35
|
).get_latest_revision_as_object()
|
|
36
|
+
page_perms = page.permissions_for_user(self.request.user)
|
|
37
|
+
if not page_perms.can_edit():
|
|
38
|
+
raise PermissionDenied
|
|
39
|
+
return page
|
|
36
40
|
|
|
37
41
|
def get_form(self, query_dict):
|
|
38
42
|
form_class = self.object.get_edit_handler().get_form_class()
|
|
@@ -87,6 +91,11 @@ class PreviewOnCreate(PreviewOnEdit):
|
|
|
87
91
|
|
|
88
92
|
page = content_type.model_class()()
|
|
89
93
|
parent_page = get_object_or_404(Page, id=parent_page_id).specific
|
|
94
|
+
|
|
95
|
+
parent_page_perms = parent_page.permissions_for_user(self.request.user)
|
|
96
|
+
if not parent_page_perms.can_add_subpage():
|
|
97
|
+
raise PermissionDenied
|
|
98
|
+
|
|
90
99
|
# We need to populate treebeard's path / depth fields in order to
|
|
91
100
|
# pass validation. We can't make these 100% consistent with the rest
|
|
92
101
|
# of the tree without making actual database changes (such as
|
wagtail/blocks/struct_block.py
CHANGED
|
@@ -427,7 +427,8 @@ class StructBlockAdapter(Adapter):
|
|
|
427
427
|
if block.meta.form_template:
|
|
428
428
|
meta["formTemplate"] = block.render_form_template()
|
|
429
429
|
|
|
430
|
-
|
|
430
|
+
# Check specifically for None to allow for empty string
|
|
431
|
+
if block.meta.label_format is not None:
|
|
431
432
|
meta["labelFormat"] = block.meta.label_format
|
|
432
433
|
|
|
433
434
|
return [
|