Do not register 'view' permission if inspect view is not enabled

pull/12001/head
Sage Abdullah 2024-07-02 10:02:19 +01:00
rodzic b3e87bcee8
commit 2fc7b4d5c9
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: EB1A33CC51CC0217
9 zmienionych plików z 61 dodań i 47 usunięć

Wyświetl plik

@ -18,6 +18,7 @@ Changelog
* Add alt text validation rule in the accessibility checker (Albina Starykova)
* Add a `deactivate()` method to `ProgressController` (Alex Morega)
* Allow manually specifying credentials for CloudFront frontend cache backend (Jake Howard)
* Automatically register permissions for models registered with a `ModelViewSet` (Sage Abdullah)
* Fix: Make `WAGTAILIMAGES_CHOOSER_PAGE_SIZE` setting functional again (Rohit Sharma)
* Fix: Enable `richtext` template tag to convert lazy translation values (Benjamin Bach)
* Fix: Ensure permission labels on group permissions page are translated where available (Matt Westcott)

Wyświetl plik

@ -32,6 +32,7 @@ This feature was implemented by Albina Starykova, with support from the Wagtail
* Implement a new design for locale labels in listings (Albina Starykova)
* Add a `deactivate()` method to `ProgressController` (Alex Morega)
* Allow manually specifying credentials for CloudFront frontend cache backend (Jake Howard)
* Automatically register permissions for models registered with a `ModelViewSet` (Sage Abdullah)
### Bug fixes
@ -110,11 +111,35 @@ WAGTAILFRONTENDCACHE = {
}
```
### Permissions for models in `ModelViewSet` are registered by default
### Changes to permissions registration for models with `ModelViewSet` and `SnippetViewSet`
Any models registered with a `ModelViewSet` will automatically have their permissions registered in the Groups administration area. Previously, you need to use the [`register_permissions`](register_permissions) hook to register them.
Models registered with a `ModelViewSet` will now automatically have their {class}`~django.contrib.auth.models.Permission` objects registered in the Groups administration area. Previously, you need to use the [`register_permissions`](register_permissions) hook to register them.
If you have a model registered with a `ModelViewSet` and you registered the model's permissions using the `register_permissions` hook, you can now safely remove the hook. If you wish to customize which permissions get registered for the model, you can override the {meth}`~wagtail.admin.viewsets.model.ModelViewSet.get_permissions_to_register` method.
If you have a model registered with a `ModelViewSet` and you registered the model's permissions using the `register_permissions` hook, you can now safely remove the hook.
If the viewset has {attr}`~wagtail.admin.viewsets.model.ModelViewSet.inspect_view_enabled` set to `True`, all permissions for the model are registered. Otherwise, the "view" permission is excluded from the registration.
To customize which permissions get registered for the model, you can override the {meth}`~wagtail.admin.viewsets.model.ModelViewSet.get_permissions_to_register` method.
This behavior now applies to snippets as well. Previously, the "view" permission for snippets is always registered regardless of `inspect_view_enabled`. If you wish to register the "view" permission, you can enable the inspect view:
```py
class FooViewSet(SnippetViewSet):
...
inspect_view_enabled = True
```
Alternatively, if you wish to register the "view" permission without enabling the inspect view (i.e. the previous behavior), you can override `get_permissions_to_register` like the following:
```py
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
class FooViewSet(SnippetViewSet):
def get_permissions_to_register(self):
content_type = ContentType.objects.get_for_model(self.model)
return Permission.objects.filter(content_type=content_type)
```
## Upgrade considerations - deprecation of old functionality

Wyświetl plik

@ -13,6 +13,7 @@ from django.utils.html import escape
from django.utils.timezone import make_aware
from openpyxl import load_workbook
from wagtail import hooks
from wagtail.admin.admin_url_finder import AdminURLFinder
from wagtail.log_actions import log
from wagtail.models import ModelLogEntry
@ -1390,6 +1391,25 @@ class TestInspectView(WagtailTestUtils, TestCase):
self.assertEqual(fields, expected_fields)
self.assertEqual(values, expected_values)
def test_view_permission_registered(self):
content_type = ContentType.objects.get_for_model(FeatureCompleteToy)
qs = Permission.objects.none()
for fn in hooks.get_hooks("register_permissions"):
qs |= fn()
registered_user_permissions = qs.filter(content_type=content_type)
self.assertEqual(
set(registered_user_permissions.values_list("codename", flat=True)),
{
"add_featurecompletetoy",
"change_featurecompletetoy",
"delete_featurecompletetoy",
# The "view" permission should be registered if inspect view is enabled
"view_featurecompletetoy",
# Any custom permissions should be registered too
"can_set_release_date",
},
)
def test_disabled(self):
# An alternate viewset for the same model without inspect_view_enabled = True
with self.assertRaises(NoReverseMatch):

Wyświetl plik

@ -1,5 +1,6 @@
from warnings import warn
from django.contrib.auth import get_permission_codename
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured
@ -623,10 +624,18 @@ class ModelViewSet(ViewSet):
"""
Returns a queryset of :class:`~django.contrib.auth.models.Permission`
objects to be registered with the :ref:`register_permissions` hook. By
default, it returns all permissions for the model.
default, it returns all permissions for the model if
:attr:`inspect_view_enabled` is set to ``True``. Otherwise, the "view"
permission is excluded.
"""
content_type = ContentType.objects.get_for_model(self.model)
return Permission.objects.filter(content_type=content_type)
permissions = Permission.objects.filter(content_type=content_type)
# Only register the "view" permission if the inspect view is enabled
if not self.inspect_view_enabled:
permissions = permissions.exclude(
codename=get_permission_codename("view", self.model_opts)
)
return permissions
def register_permissions(self):
hooks.register("register_permissions", self.get_permissions_to_register)

Wyświetl plik

@ -117,11 +117,3 @@ class LocaleViewSet(ModelViewSet):
def get_form_class(self, for_update=False):
return LocaleForm
def get_permissions_to_register(self):
# Only register these permissions (and not others e.g. "view_locale")
return (
super()
.get_permissions_to_register()
.filter(codename__in=["add_locale", "change_locale", "delete_locale"])
)

Wyświetl plik

@ -75,11 +75,3 @@ class SiteViewSet(ModelViewSet):
def get_form_class(self, for_update=False):
return SiteForm
def get_permissions_to_register(self):
# Only register these permissions (and not others e.g. "view_site")
return (
super()
.get_permissions_to_register()
.filter(codename__in=["add_site", "change_site", "delete_site"])
)

Wyświetl plik

@ -2397,7 +2397,7 @@ class TestGroupEditView(AdminTemplateTestUtils, WagtailTestUtils, TestCase):
def test_is_custom_permission_checked(self):
# Add a permission from the 'custom permission' column to the user's group
custom_permission = Permission.objects.get(codename="view_fancysnippet")
custom_permission = Permission.objects.get(codename="view_fullfeaturedsnippet")
self.test_group.permissions.add(custom_permission)
response = self.get()

Wyświetl plik

@ -190,11 +190,3 @@ class GroupViewSet(ModelViewSet):
return super().get_urlpatterns() + [
re_path(r"(\d+)/users/$", self.users_view, name="users"),
]
def get_permissions_to_register(self):
# Only register these permissions (and not others e.g. "view_group")
return (
super()
.get_permissions_to_register()
.filter(codename__in=["add_group", "change_group", "delete_group"])
)

Wyświetl plik

@ -3,7 +3,6 @@ from warnings import warn
import django_filters
from django.conf import settings
from django.contrib.auth import (
get_permission_codename,
get_user_model,
update_session_auth_hash,
)
@ -399,19 +398,3 @@ class UserViewSet(ModelViewSet):
if for_update:
return get_user_edit_form()
return get_user_creation_form()
def get_permissions_to_register(self):
# Only register these permissions (and not others e.g. "view_user")
# and use the model's meta to get the permission codenames in case the
# AUTH_USER_MODEL setting has been changed
return (
super()
.get_permissions_to_register()
.filter(
codename__in=[
get_permission_codename("add", self.model._meta),
get_permission_codename("change", self.model._meta),
get_permission_codename("delete", self.model._meta),
]
)
)