Allow displaying permissions linked to the Admin model's content type (#11668)

pull/11620/head
Sage Abdullah 2024-02-15 17:28:44 +00:00 zatwierdzone przez Matt Westcott
rodzic 2594be387d
commit bded2cb98b
5 zmienionych plików z 84 dodań i 10 usunięć

Wyświetl plik

@ -11,6 +11,7 @@ Changelog
* Add the ability to disable the usage of a shared password for enhanced security for the private pages and collections (documents) feature (Salvo Polizzi, Jake Howard) * Add the ability to disable the usage of a shared password for enhanced security for the private pages and collections (documents) feature (Salvo Polizzi, Jake Howard)
* Add system checks to ensure that `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` are correctly configured (Rohit Sharma, Coen van der Kamp) * Add system checks to ensure that `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` are correctly configured (Rohit Sharma, Coen van der Kamp)
* Allow custom permissions with the same prefix as built-in permissions (Sage Abdullah) * Allow custom permissions with the same prefix as built-in permissions (Sage Abdullah)
* Allow displaying permissions linked to the Admin model's content type (Sage Abdullah)
* Fix: Fix typo in `__str__` for MySQL search index (Jake Howard) * Fix: Fix typo in `__str__` for MySQL search index (Jake Howard)
* Fix: Ensure that unit tests correctly check for migrations in all core Wagtail apps (Matt Westcott) * Fix: Ensure that unit tests correctly check for migrations in all core Wagtail apps (Matt Westcott)
* Fix: Correctly handle `date` objects on `human_readable_date` template tag (Jhonatan Lopes) * Fix: Correctly handle `date` objects on `human_readable_date` template tag (Jhonatan Lopes)

Wyświetl plik

@ -20,6 +20,7 @@ depth: 1
* Add the ability to disable the usage of a shared password for enhanced security for the [private pages](private_pages) and [collections (documents)](private_collections) feature (Salvo Polizzi, Jake Howard) * Add the ability to disable the usage of a shared password for enhanced security for the [private pages](private_pages) and [collections (documents)](private_collections) feature (Salvo Polizzi, Jake Howard)
* Add system checks to ensure that `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` are [correctly configured](wagtail_date_time_formats) (Rohit Sharma, Coen van der Kamp) * Add system checks to ensure that `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` are [correctly configured](wagtail_date_time_formats) (Rohit Sharma, Coen van der Kamp)
* Allow custom permissions with the same prefix as built-in permissions (Sage Abdullah) * Allow custom permissions with the same prefix as built-in permissions (Sage Abdullah)
* Allow displaying permissions linked to the Admin model's content type (Sage Abdullah)
### Bug fixes ### Bug fixes

Wyświetl plik

@ -67,9 +67,29 @@ See Django's documentation on [custom permissions](https://docs.djangoproject.co
The ability to have custom permissions with codenames starting with `add_`, `change_`, or `delete_` was added. The ability to have custom permissions with codenames starting with `add_`, `change_`, or `delete_` was added.
``` ```
## Displaying custom permissions in the admin Permissions for models registered with Wagtail will automatically show up in the Wagtail admin Group edit form. For other models, you can also add the permissions using the `register_permissions` hook (see [](register_permissions)).
Most permissions will automatically show up in the Wagtail admin Group edit form, however, you can also add them using the `register_permissions` hook (see [](register_permissions)). To add a custom permission to be used in the Wagtail admin without relating to a specific model, you can create it using the content type of the `wagtail.admin.models.Admin` model. For example:
```python
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from wagtail.admin.models import Admin
content_type = ContentType.objects.get_for_model(Admin)
permission = Permission.objects.create(
content_type=content_type,
codename="can_do_something",
name="Can do something",
)
```
After registering the permission using the `register_permissions` hook, it will be displayed in the Wagtail admin Group edit form under the 'Other permissions' section, alongside the 'Can access Wagtail admin' permission.
```{versionadded} 6.1
The ability to register custom permissions in the "Other permissions" section was added.
```
## `FieldPanel` and `PanelGroup` permissions ## `FieldPanel` and `PanelGroup` permissions

Wyświetl plik

@ -4,9 +4,11 @@ from collections import defaultdict
from django import template from django import template
from django.contrib.auth import get_permission_codename from django.contrib.auth import get_permission_codename
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.utils.text import camel_case_to_spaces from django.utils.text import camel_case_to_spaces
from wagtail import hooks from wagtail import hooks
from wagtail.admin.models import Admin
from wagtail.users.permission_order import CONTENT_TYPE_ORDER from wagtail.users.permission_order import CONTENT_TYPE_ORDER
register = template.Library() register = template.Library()
@ -97,9 +99,6 @@ def format_permissions(permission_bound_field):
for checkbox in permission_bound_field for checkbox in permission_bound_field
} }
object_perms = []
other_perms = []
# Permissions that are known by Wagtail, to be shown under their own columns. # Permissions that are known by Wagtail, to be shown under their own columns.
# Other permissions will be shown under the "custom permissions" column. # Other permissions will be shown under the "custom permissions" column.
main_permission_names = ["add", "change", "delete", "publish", "lock", "unlock"] main_permission_names = ["add", "change", "delete", "publish", "lock", "unlock"]
@ -118,17 +117,29 @@ def format_permissions(permission_bound_field):
for permission in permissions: for permission in permissions:
content_perms_by_ct_id[permission.content_type_id].append(permission) content_perms_by_ct_id[permission.content_type_id].append(permission)
# Permissions that use Wagtail's Admin content type, to be displayed
# under the "Other permissions" section alongside the
# "Can access Wagtail admin" permission.
admin_content_type = ContentType.objects.get_for_model(Admin)
admin_permissions = content_perms_by_ct_id.pop(admin_content_type.id, [])
other_perms = [(perm, checkboxes_by_id[perm.id]) for perm in admin_permissions]
# We're done with the admin content type, so remove it from the list of content types
# but make sure the sorted order is preserved.
content_type_ids = [
ct_id for ct_id in content_type_ids if ct_id != admin_content_type.pk
]
# Permissions for all other content types, to be displayed under the
# "Object permissions" section.
object_perms = []
# Iterate using the sorted content_type_ids # Iterate using the sorted content_type_ids
for ct_id in content_type_ids: for ct_id in content_type_ids:
content_perms = content_perms_by_ct_id[ct_id] content_perms = content_perms_by_ct_id[ct_id]
content_perms_dict = {} content_perms_dict = {}
custom_perms = [] custom_perms = []
if content_perms[0].content_type.name == "admin":
perm = content_perms[0]
other_perms.append((perm, checkboxes_by_id[perm.id]))
continue
for perm in content_perms: for perm in content_perms:
content_perms_dict["object"] = perm.content_type.name content_perms_dict["object"] = perm.content_type.name
checkbox = checkboxes_by_id[perm.id] checkbox = checkboxes_by_id[perm.id]

Wyświetl plik

@ -5,6 +5,7 @@ from django.apps import apps
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.models import Q from django.db.models import Q
@ -14,6 +15,7 @@ from django.urls import reverse
from wagtail import hooks from wagtail import hooks
from wagtail.admin.admin_url_finder import AdminURLFinder from wagtail.admin.admin_url_finder import AdminURLFinder
from wagtail.admin.models import Admin
from wagtail.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME from wagtail.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME
from wagtail.models import ( from wagtail.models import (
Collection, Collection,
@ -1637,6 +1639,45 @@ class TestGroupCreateView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
) )
) )
def test_custom_other_permissions_with_wagtail_admin_content_type(self):
"""
https://github.com/wagtail/wagtail/issues/8086
Allow custom permissions using Wagtail's Admin content type to be
displayed in the "Other permissions" section.
"""
admin_ct = ContentType.objects.get_for_model(Admin)
custom_permission = Permission.objects.create(
codename="roadmap_sync",
name="Can sync roadmap items from GitHub",
content_type=admin_ct,
)
with self.register_hook(
"register_permissions",
lambda: Permission.objects.filter(
codename="roadmap_sync", content_type=admin_ct
),
):
response = self.get()
soup = self.get_soup(response.content)
other_permissions = soup.select_one("#other-permissions-section")
self.assertIsNotNone(other_permissions)
custom_checkbox = other_permissions.select_one(
f'input[value="{custom_permission.pk}"]'
)
self.assertIsNotNone(custom_checkbox)
custom_label = other_permissions.select_one(
f'label[for="{custom_checkbox.attrs.get("id")}"]'
)
self.assertIsNotNone(custom_label)
self.assertEqual(
custom_label.get_text(strip=True), "Can sync roadmap items from GitHub"
)
class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase): class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
def setUp(self): def setUp(self):