wagtail 6.0.2__py3-none-any.whl → 6.0.4__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.
@@ -27,6 +27,7 @@ from django.views.generic.edit import (
27
27
  from wagtail.actions.unpublish import UnpublishAction
28
28
  from wagtail.admin import messages
29
29
  from wagtail.admin.filters import WagtailFilterSet
30
+ from wagtail.admin.forms.models import WagtailAdminModelForm
30
31
  from wagtail.admin.forms.search import SearchForm
31
32
  from wagtail.admin.panels import get_edit_handler
32
33
  from wagtail.admin.ui.components import Component, MediaContainer
@@ -616,6 +617,24 @@ class CreateView(
616
617
  for locale in Locale.objects.all().exclude(id=self.locale.id)
617
618
  ]
618
619
 
620
+ def get_initial_form_instance(self):
621
+ if self.locale:
622
+ instance = self.model()
623
+ instance.locale = self.locale
624
+ return instance
625
+
626
+ def get_form_kwargs(self):
627
+ if instance := self.get_initial_form_instance():
628
+ # super().get_form_kwargs() will use self.object as the instance kwarg
629
+ self.object = instance
630
+ kwargs = super().get_form_kwargs()
631
+
632
+ form_class = self.get_form_class()
633
+ # Add for_user support for PermissionedForm
634
+ if issubclass(form_class, WagtailAdminModelForm):
635
+ kwargs["for_user"] = self.request.user
636
+ return kwargs
637
+
619
638
  def save_instance(self):
620
639
  """
621
640
  Called after the form is successfully validated - saves the object to the db
@@ -657,12 +676,18 @@ class CreateView(
657
676
  return super().form_invalid(form)
658
677
 
659
678
 
660
- class CopyView(CreateView):
679
+ class CopyViewMixin:
661
680
  def get_object(self, queryset=None):
662
- return get_object_or_404(self.model, pk=self.kwargs["pk"])
681
+ return get_object_or_404(
682
+ self.model, pk=unquote(str(self.kwargs[self.pk_url_kwarg]))
683
+ )
663
684
 
664
- def get_form_kwargs(self):
665
- return {**super().get_form_kwargs(), "instance": self.get_object()}
685
+ def get_initial_form_instance(self):
686
+ return self.get_object()
687
+
688
+
689
+ class CopyView(CopyViewMixin, CreateView):
690
+ pass
666
691
 
667
692
 
668
693
  class EditView(
@@ -786,6 +811,13 @@ class EditView(
786
811
  for translation in self.object.get_translations().select_related("locale")
787
812
  ]
788
813
 
814
+ def get_form_kwargs(self):
815
+ kwargs = super().get_form_kwargs()
816
+ form_class = self.get_form_class()
817
+ if issubclass(form_class, WagtailAdminModelForm):
818
+ kwargs["for_user"] = self.request.user
819
+ return kwargs
820
+
789
821
  def save_instance(self):
790
822
  """
791
823
  Called after the form is successfully validated - saves the object to the db.
@@ -162,6 +162,7 @@ class BaseSearchView(PermissionCheckedMixin, BaseListingView):
162
162
  def get_table_kwargs(self):
163
163
  kwargs = super().get_table_kwargs()
164
164
  kwargs["show_locale_labels"] = self.show_locale_labels
165
+ kwargs["actions_next_url"] = self.get_index_url()
165
166
  return kwargs
166
167
 
167
168
  def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
@@ -14,6 +14,7 @@ from wagtail.test.testapp.models import (
14
14
  PanelGenericSettings,
15
15
  TabbedGenericSettings,
16
16
  TestGenericSetting,
17
+ TestPermissionedGenericSetting,
17
18
  )
18
19
  from wagtail.test.utils import WagtailTestUtils
19
20
 
@@ -76,6 +77,11 @@ class BaseTestGenericSettingView(WagtailTestUtils, TestCase):
76
77
  class TestGenericSettingCreateView(BaseTestGenericSettingView):
77
78
  def setUp(self):
78
79
  self.user = self.login()
80
+ self.user.user_permissions.add(
81
+ Permission.objects.get(
82
+ content_type__app_label="wagtailadmin", codename="access_admin"
83
+ )
84
+ )
79
85
 
80
86
  def test_get_edit(self):
81
87
  response = self.get()
@@ -107,6 +113,38 @@ class TestGenericSettingCreateView(BaseTestGenericSettingView):
107
113
  # Ensure the form supports file uploads
108
114
  self.assertContains(response, 'enctype="multipart/form-data"')
109
115
 
116
+ def test_create_restricted_field_without_permission(self):
117
+ self.user.is_superuser = False
118
+ self.user.save()
119
+
120
+ self.assertFalse(TestPermissionedGenericSetting.objects.exists())
121
+ response = self.post(
122
+ post_data={"sensitive_email": "test@example.com", "title": "test"},
123
+ setting=TestPermissionedGenericSetting,
124
+ )
125
+ self.assertEqual(response.status_code, 302)
126
+
127
+ settings = TestPermissionedGenericSetting.objects.get()
128
+ self.assertEqual(settings.title, "test")
129
+ self.assertEqual(settings.sensitive_email, "")
130
+
131
+ def test_create_restricted_field(self):
132
+ self.user.is_superuser = False
133
+ self.user.save()
134
+ self.user.user_permissions.add(
135
+ Permission.objects.get(codename="can_edit_sensitive_email_generic_setting")
136
+ )
137
+ self.assertFalse(TestPermissionedGenericSetting.objects.exists())
138
+ response = self.post(
139
+ post_data={"sensitive_email": "test@example.com", "title": "test"},
140
+ setting=TestPermissionedGenericSetting,
141
+ )
142
+ self.assertEqual(response.status_code, 302)
143
+
144
+ settings = TestPermissionedGenericSetting.objects.get()
145
+ self.assertEqual(settings.title, "test")
146
+ self.assertEqual(settings.sensitive_email, "test@example.com")
147
+
110
148
 
111
149
  class TestGenericSettingEditView(BaseTestGenericSettingView):
112
150
  def setUp(self):
@@ -114,7 +152,12 @@ class TestGenericSettingEditView(BaseTestGenericSettingView):
114
152
  self.test_setting.title = "Setting title"
115
153
  self.test_setting.save()
116
154
 
117
- self.login()
155
+ self.user = self.login()
156
+ self.user.user_permissions.add(
157
+ Permission.objects.get(
158
+ content_type__app_label="wagtailadmin", codename="access_admin"
159
+ )
160
+ )
118
161
 
119
162
  def test_get_edit(self):
120
163
  response = self.get()
@@ -153,6 +196,50 @@ class TestGenericSettingEditView(BaseTestGenericSettingView):
153
196
  expected_url=f"{url}{TestGenericSetting.objects.first().pk}/",
154
197
  )
155
198
 
199
+ def test_edit_restricted_field(self):
200
+ test_setting = TestPermissionedGenericSetting()
201
+ test_setting.sensitive_email = "test@example.com"
202
+ test_setting.save()
203
+ self.user.is_superuser = False
204
+ self.user.save()
205
+
206
+ self.user.user_permissions.add(
207
+ Permission.objects.get(codename="can_edit_sensitive_email_generic_setting")
208
+ )
209
+
210
+ response = self.get(setting=TestPermissionedGenericSetting)
211
+ self.assertEqual(response.status_code, 200)
212
+ self.assertIn("sensitive_email", list(response.context["form"].fields))
213
+
214
+ response = self.post(
215
+ setting=TestPermissionedGenericSetting,
216
+ post_data={"sensitive_email": "test-updated@example.com", "title": "title"},
217
+ )
218
+ self.assertEqual(response.status_code, 302)
219
+
220
+ test_setting.refresh_from_db()
221
+ self.assertEqual(test_setting.sensitive_email, "test-updated@example.com")
222
+
223
+ def test_edit_restricted_field_without_permission(self):
224
+ test_setting = TestPermissionedGenericSetting()
225
+ test_setting.sensitive_email = "test@example.com"
226
+ test_setting.save()
227
+ self.user.is_superuser = False
228
+ self.user.save()
229
+
230
+ response = self.get(setting=TestPermissionedGenericSetting)
231
+ self.assertEqual(response.status_code, 200)
232
+ self.assertNotIn("sensitive_email", list(response.context["form"].fields))
233
+
234
+ response = self.post(
235
+ setting=TestPermissionedGenericSetting,
236
+ post_data={"sensitive_email": "test-updated@example.com", "title": "title"},
237
+ )
238
+ self.assertEqual(response.status_code, 302)
239
+
240
+ test_setting.refresh_from_db()
241
+ self.assertEqual(test_setting.sensitive_email, "test@example.com")
242
+
156
243
 
157
244
  class TestAdminPermission(WagtailTestUtils, TestCase):
158
245
  def test_registered_permission(self):
@@ -14,6 +14,7 @@ from wagtail.test.testapp.models import (
14
14
  IconSiteSetting,
15
15
  PanelSiteSettings,
16
16
  TabbedSiteSettings,
17
+ TestPermissionedSiteSetting,
17
18
  TestSiteSetting,
18
19
  )
19
20
  from wagtail.test.utils import WagtailTestUtils
@@ -72,6 +73,11 @@ class BaseTestSiteSettingView(WagtailTestUtils, TestCase):
72
73
  class TestSiteSettingCreateView(BaseTestSiteSettingView):
73
74
  def setUp(self):
74
75
  self.user = self.login()
76
+ self.user.user_permissions.add(
77
+ Permission.objects.get(
78
+ content_type__app_label="wagtailadmin", codename="access_admin"
79
+ )
80
+ )
75
81
 
76
82
  def test_get_edit(self):
77
83
  response = self.get()
@@ -103,18 +109,55 @@ class TestSiteSettingCreateView(BaseTestSiteSettingView):
103
109
  # Ensure the form supports file uploads
104
110
  self.assertContains(response, 'enctype="multipart/form-data"')
105
111
 
112
+ def test_create_restricted_field_without_permission(self):
113
+ self.user.is_superuser = False
114
+ self.user.save()
115
+
116
+ self.assertFalse(TestPermissionedSiteSetting.objects.exists())
117
+ response = self.post(
118
+ post_data={"sensitive_email": "test@example.com", "title": "test"},
119
+ setting=TestPermissionedSiteSetting,
120
+ )
121
+ self.assertEqual(response.status_code, 302)
122
+
123
+ settings = TestPermissionedSiteSetting.objects.get()
124
+ self.assertEqual(settings.title, "test")
125
+ self.assertEqual(settings.sensitive_email, "")
126
+
127
+ def test_create_restricted_field(self):
128
+ self.user.is_superuser = False
129
+ self.user.save()
130
+ self.user.user_permissions.add(
131
+ Permission.objects.get(codename="can_edit_sensitive_email_site_setting")
132
+ )
133
+ self.assertFalse(TestPermissionedSiteSetting.objects.exists())
134
+ response = self.post(
135
+ post_data={"sensitive_email": "test@example.com", "title": "test"},
136
+ setting=TestPermissionedSiteSetting,
137
+ )
138
+ self.assertEqual(response.status_code, 302)
139
+
140
+ settings = TestPermissionedSiteSetting.objects.get()
141
+ self.assertEqual(settings.title, "test")
142
+ self.assertEqual(settings.sensitive_email, "test@example.com")
143
+
106
144
 
107
145
  class TestSiteSettingEditView(BaseTestSiteSettingView):
108
146
  def setUp(self):
109
- default_site = Site.objects.get(is_default_site=True)
147
+ self.default_site = Site.objects.get(is_default_site=True)
110
148
 
111
149
  self.test_setting = TestSiteSetting()
112
150
  self.test_setting.title = "Site title"
113
151
  self.test_setting.email = "initial@example.com"
114
- self.test_setting.site = default_site
152
+ self.test_setting.site = self.default_site
115
153
  self.test_setting.save()
116
154
 
117
- self.login()
155
+ self.user = self.login()
156
+ self.user.user_permissions.add(
157
+ Permission.objects.get(
158
+ content_type__app_label="wagtailadmin", codename="access_admin"
159
+ )
160
+ )
118
161
 
119
162
  def test_get_edit(self):
120
163
  response = self.get()
@@ -158,6 +201,52 @@ class TestSiteSettingEditView(BaseTestSiteSettingView):
158
201
  response = self.client.get(url)
159
202
  self.assertRedirects(response, status_code=302, expected_url="/admin/")
160
203
 
204
+ def test_edit_restricted_field(self):
205
+ test_setting = TestPermissionedSiteSetting()
206
+ test_setting.sensitive_email = "test@example.com"
207
+ test_setting.site = self.default_site
208
+ test_setting.save()
209
+ self.user.is_superuser = False
210
+ self.user.save()
211
+
212
+ self.user.user_permissions.add(
213
+ Permission.objects.get(codename="can_edit_sensitive_email_site_setting")
214
+ )
215
+
216
+ response = self.get(setting=TestPermissionedSiteSetting)
217
+ self.assertEqual(response.status_code, 200)
218
+ self.assertIn("sensitive_email", list(response.context["form"].fields))
219
+
220
+ response = self.post(
221
+ setting=TestPermissionedSiteSetting,
222
+ post_data={"sensitive_email": "test-updated@example.com", "title": "title"},
223
+ )
224
+ self.assertEqual(response.status_code, 302)
225
+
226
+ test_setting.refresh_from_db()
227
+ self.assertEqual(test_setting.sensitive_email, "test-updated@example.com")
228
+
229
+ def test_edit_restricted_field_without_permission(self):
230
+ test_setting = TestPermissionedSiteSetting()
231
+ test_setting.sensitive_email = "test@example.com"
232
+ test_setting.site = self.default_site
233
+ test_setting.save()
234
+ self.user.is_superuser = False
235
+ self.user.save()
236
+
237
+ response = self.get(setting=TestPermissionedSiteSetting)
238
+ self.assertEqual(response.status_code, 200)
239
+ self.assertNotIn("sensitive_email", list(response.context["form"].fields))
240
+
241
+ response = self.post(
242
+ setting=TestPermissionedSiteSetting,
243
+ post_data={"sensitive_email": "test-updated@example.com", "title": "title"},
244
+ )
245
+ self.assertEqual(response.status_code, 302)
246
+
247
+ test_setting.refresh_from_db()
248
+ self.assertEqual(test_setting.sensitive_email, "test@example.com")
249
+
161
250
 
162
251
  @override_settings(
163
252
  ALLOWED_HOSTS=["testserver", "example.com", "noneoftheabove.example.com"]
@@ -1,6 +1,7 @@
1
1
  from django.test import TestCase
2
2
  from django.urls import reverse
3
3
 
4
+ from wagtail.admin.staticfiles import versioned_static
4
5
  from wagtail.test.utils import WagtailTestUtils
5
6
 
6
7
 
@@ -13,3 +14,10 @@ class TestStyleGuide(WagtailTestUtils, TestCase):
13
14
 
14
15
  self.assertEqual(response.status_code, 200)
15
16
  self.assertTemplateUsed(response, "wagtailstyleguide/base.html")
17
+
18
+ custom_css = versioned_static("wagtailstyleguide/css/animate-progress.css")
19
+ widget_css = versioned_static("wagtailadmin/css/panels/draftail.css")
20
+ widget_js = versioned_static("wagtailadmin/js/draftail.js")
21
+ self.assertContains(response, custom_css)
22
+ self.assertContains(response, widget_css)
23
+ self.assertContains(response, widget_js)
@@ -94,7 +94,7 @@ class ExampleForm(forms.Form):
94
94
 
95
95
  @property
96
96
  def media(self):
97
- return forms.Media(
97
+ return super().media + forms.Media(
98
98
  css={
99
99
  "all": [versioned_static("wagtailstyleguide/css/animate-progress.css")]
100
100
  }
@@ -0,0 +1,43 @@
1
+ from django.apps import apps
2
+ from django.core.management.base import BaseCommand
3
+ from django.db import connection, models
4
+
5
+ from wagtail.models import (
6
+ BaseLogEntry,
7
+ BootstrapTranslatableMixin,
8
+ ReferenceIndex,
9
+ TranslatableMixin,
10
+ )
11
+
12
+
13
+ class Command(BaseCommand):
14
+ help = "Converts UUID columns from char type to the native UUID type used in MariaDB 10.7+ and Django 5.0+."
15
+
16
+ def convert_field(self, model, field_name, null=False):
17
+ if model._meta.get_field(field_name).model != model:
18
+ # Field is inherited from a parent model
19
+ return
20
+
21
+ if not model._meta.managed:
22
+ # The migration framework skips unmanaged models, so we should too
23
+ return
24
+
25
+ old_field = models.CharField(null=null, max_length=36)
26
+ old_field.set_attributes_from_name(field_name)
27
+
28
+ new_field = models.UUIDField(null=null)
29
+ new_field.set_attributes_from_name(field_name)
30
+
31
+ with connection.schema_editor() as schema_editor:
32
+ schema_editor.alter_field(model, old_field, new_field)
33
+
34
+ def handle(self, **options):
35
+ self.convert_field(ReferenceIndex, "content_path_hash")
36
+
37
+ for model in apps.get_models():
38
+ if issubclass(model, BaseLogEntry):
39
+ self.convert_field(model, "uuid", null=True)
40
+ elif issubclass(model, BootstrapTranslatableMixin):
41
+ self.convert_field(model, "translation_key", null=True)
42
+ elif issubclass(model, TranslatableMixin):
43
+ self.convert_field(model, "translation_key")
@@ -35,7 +35,6 @@ from wagtail.snippets.action_menu import (
35
35
  )
36
36
  from wagtail.snippets.blocks import SnippetChooserBlock
37
37
  from wagtail.snippets.models import SNIPPET_MODELS, register_snippet
38
- from wagtail.snippets.views.snippets import CopyView
39
38
  from wagtail.snippets.widgets import (
40
39
  AdminSnippetChooser,
41
40
  SnippetChooserAdapter,
@@ -974,20 +973,29 @@ class TestSnippetCopyView(WagtailTestUtils, TestCase):
974
973
  StandardSnippet.snippet_viewset.get_url_name("copy"),
975
974
  args=(self.snippet.pk,),
976
975
  )
977
- self.login()
976
+ self.user = self.login()
977
+
978
+ def test_without_permission(self):
979
+ self.user.is_superuser = False
980
+ self.user.save()
981
+ admin_permission = Permission.objects.get(
982
+ content_type__app_label="wagtailadmin", codename="access_admin"
983
+ )
984
+ self.user.user_permissions.add(admin_permission)
978
985
 
979
- def test_simple(self):
986
+ response = self.client.get(self.url)
987
+ self.assertEqual(response.status_code, 302)
988
+ self.assertRedirects(response, reverse("wagtailadmin_home"))
989
+
990
+ def test_form_is_prefilled(self):
980
991
  response = self.client.get(self.url)
981
992
  self.assertEqual(response.status_code, 200)
982
993
  self.assertTemplateUsed(response, "wagtailsnippets/snippets/create.html")
983
994
 
984
- def test_form_prefilled(self):
985
- request = RequestFactory().get(self.url)
986
- view = CopyView()
987
- view.model = StandardSnippet
988
- view.setup(request, pk=self.snippet.pk)
989
-
990
- self.assertEqual(view._get_initial_form_instance(), self.snippet)
995
+ # Ensure form is prefilled
996
+ soup = self.get_soup(response.content)
997
+ text_input = soup.select_one('input[name="text"]')
998
+ self.assertEqual(text_input.attrs.get("value"), "Test snippet")
991
999
 
992
1000
 
993
1001
  @override_settings(WAGTAIL_I18N_ENABLED=True)
@@ -5,7 +5,7 @@ from django.contrib.admin.utils import quote
5
5
  from django.core import checks
6
6
  from django.core.exceptions import ImproperlyConfigured, PermissionDenied
7
7
  from django.http import Http404
8
- from django.shortcuts import get_object_or_404, redirect
8
+ from django.shortcuts import redirect
9
9
  from django.urls import path, re_path, reverse, reverse_lazy
10
10
  from django.utils.functional import cached_property
11
11
  from django.utils.text import capfirst
@@ -235,22 +235,6 @@ class CreateView(generic.CreateEditViewOptionalFeaturesMixin, generic.CreateView
235
235
  def _get_action_menu(self):
236
236
  return SnippetActionMenu(self.request, view=self.view_name, model=self.model)
237
237
 
238
- def _get_initial_form_instance(self):
239
- instance = self.model()
240
-
241
- # Set locale of the new instance
242
- if self.locale:
243
- instance.locale = self.locale
244
-
245
- return instance
246
-
247
- def get_form_kwargs(self):
248
- return {
249
- **super().get_form_kwargs(),
250
- "instance": self._get_initial_form_instance(),
251
- "for_user": self.request.user,
252
- }
253
-
254
238
  def get_side_panels(self):
255
239
  side_panels = [
256
240
  SnippetStatusSidePanel(
@@ -280,16 +264,8 @@ class CreateView(generic.CreateEditViewOptionalFeaturesMixin, generic.CreateView
280
264
  return context
281
265
 
282
266
 
283
- class CopyView(CreateView):
284
- def get_object(self):
285
- return get_object_or_404(self.model, pk=self.kwargs["pk"])
286
-
287
- def _get_initial_form_instance(self):
288
- instance = self.get_object()
289
- # Set locale of the new instance
290
- if self.locale:
291
- instance.locale = self.locale
292
- return instance
267
+ class CopyView(generic.CopyViewMixin, CreateView):
268
+ pass
293
269
 
294
270
 
295
271
  class EditView(generic.CreateEditViewOptionalFeaturesMixin, generic.EditView):
@@ -310,9 +286,6 @@ class EditView(generic.CreateEditViewOptionalFeaturesMixin, generic.EditView):
310
286
  locked_for_user=self.locked_for_user,
311
287
  )
312
288
 
313
- def get_form_kwargs(self):
314
- return {**super().get_form_kwargs(), "for_user": self.request.user}
315
-
316
289
  def get_side_panels(self):
317
290
  side_panels = [
318
291
  SnippetStatusSidePanel(
@@ -0,0 +1,42 @@
1
+ # Generated by Django 4.2.11 on 2024-04-25 15:51
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wagtailcore', '0091_remove_revision_submitted_for_moderation'),
11
+ ('tests', '0033_customcopyformpage'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.CreateModel(
16
+ name='TestPermissionedGenericSetting',
17
+ fields=[
18
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19
+ ('title', models.CharField(max_length=100)),
20
+ ('sensitive_email', models.EmailField(max_length=50)),
21
+ ],
22
+ options={
23
+ 'permissions': [('can_edit_sensitive_email_generic_setting', 'Can edit sensitive email generic setting.')],
24
+ },
25
+ ),
26
+ migrations.AlterModelOptions(
27
+ name='featurecompletetoy',
28
+ options={'permissions': [('can_set_release_date', 'Can set release date')]},
29
+ ),
30
+ migrations.CreateModel(
31
+ name='TestPermissionedSiteSetting',
32
+ fields=[
33
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
34
+ ('title', models.CharField(max_length=100)),
35
+ ('sensitive_email', models.EmailField(max_length=50)),
36
+ ('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.site')),
37
+ ],
38
+ options={
39
+ 'permissions': [('can_edit_sensitive_email_site_setting', 'Can edit sensitive email site setting.')],
40
+ },
41
+ ),
42
+ ]
@@ -1640,6 +1640,49 @@ class TestGenericSetting(BaseGenericSetting):
1640
1640
  email = models.EmailField(max_length=50)
1641
1641
 
1642
1642
 
1643
+ @register_setting
1644
+ class TestPermissionedGenericSetting(BaseGenericSetting):
1645
+ title = models.CharField(max_length=100)
1646
+ sensitive_email = models.EmailField(max_length=50)
1647
+
1648
+ panels = [
1649
+ FieldPanel("title"),
1650
+ FieldPanel(
1651
+ "sensitive_email",
1652
+ permission="tests.can_edit_sensitive_email_generic_setting",
1653
+ ),
1654
+ ]
1655
+
1656
+ class Meta:
1657
+ permissions = [
1658
+ (
1659
+ "can_edit_sensitive_email_generic_setting",
1660
+ "Can edit sensitive email generic setting.",
1661
+ ),
1662
+ ]
1663
+
1664
+
1665
+ @register_setting
1666
+ class TestPermissionedSiteSetting(BaseSiteSetting):
1667
+ title = models.CharField(max_length=100)
1668
+ sensitive_email = models.EmailField(max_length=50)
1669
+
1670
+ panels = [
1671
+ FieldPanel("title"),
1672
+ FieldPanel(
1673
+ "sensitive_email", permission="tests.can_edit_sensitive_email_site_setting"
1674
+ ),
1675
+ ]
1676
+
1677
+ class Meta:
1678
+ permissions = [
1679
+ (
1680
+ "can_edit_sensitive_email_site_setting",
1681
+ "Can edit sensitive email site setting.",
1682
+ ),
1683
+ ]
1684
+
1685
+
1643
1686
  @register_setting
1644
1687
  class ImportantPagesSiteSetting(BaseSiteSetting):
1645
1688
  sign_up_page = models.ForeignKey(
@@ -2229,6 +2272,9 @@ class FeatureCompleteToy(index.Indexed, models.Model):
2229
2272
  def __str__(self):
2230
2273
  return f"{self.name} ({self.release_date})"
2231
2274
 
2275
+ class Meta:
2276
+ permissions = [("can_set_release_date", "Can set release date")]
2277
+
2232
2278
 
2233
2279
  class PurgeRevisionsProtectedTestModel(models.Model):
2234
2280
  revision = models.OneToOneField(
@@ -227,7 +227,7 @@ class FeatureCompleteToyViewSet(ModelViewSet):
227
227
 
228
228
  panels = [
229
229
  FieldPanel("name"),
230
- FieldPanel("release_date"),
230
+ FieldPanel("release_date", permission="tests.can_set_release_date"),
231
231
  ]
232
232
 
233
233
 
@@ -2029,7 +2029,13 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
2029
2029
  perm.content_type.model,
2030
2030
  )
2031
2031
  for perm_set in object_perms
2032
- for perm in [next(v for v in flatten(perm_set) if "perm" in v)["perm"]]
2032
+ for perm in [
2033
+ next(
2034
+ v
2035
+ for v in flatten(perm_set)
2036
+ if isinstance(v, dict) and "perm" in v
2037
+ )["perm"]
2038
+ ]
2033
2039
  ]
2034
2040
 
2035
2041
  # Set order on two objects, should appear first and second
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wagtail
3
- Version: 6.0.2
3
+ Version: 6.0.4
4
4
  Summary: A Django content management system.
5
5
  Home-page: https://wagtail.org/
6
6
  Author: Wagtail core team + contributors