diff --git a/src/documents/permissions.py b/src/documents/permissions.py index f829597b6..fb850fda9 100644 --- a/src/documents/permissions.py +++ b/src/documents/permissions.py @@ -109,20 +109,6 @@ def has_system_status_permission(user: User | None) -> bool: ) -def get_groups_with_only_permission(obj, codename): - ctype = ContentType.objects.get_for_model(obj) - permission = Permission.objects.get(content_type=ctype, codename=codename) - group_object_perm_group_ids = ( - GroupObjectPermission.objects.filter( - object_pk=obj.pk, - content_type=ctype, - ) - .filter(permission=permission) - .values_list("group_id") - ) - return Group.objects.filter(id__in=group_object_perm_group_ids).distinct() - - def _resolve_permissions(codenames: set[str], ctype: ContentType) -> list[Permission]: """ Resolve ``codenames`` to Permission rows, raising for any that don't exist diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 8dbf22887..b93a2b400 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -39,6 +39,7 @@ from drf_spectacular.utils import extend_schema_field from drf_spectacular.utils import extend_schema_serializer from drf_writable_nested.serializers import NestedUpdateMixin from guardian.core import ObjectPermissionChecker +from guardian.shortcuts import get_groups_with_perms from guardian.shortcuts import get_users_with_perms from guardian.utils import get_group_obj_perms_model from guardian.utils import get_user_obj_perms_model @@ -83,7 +84,6 @@ from documents.permissions import PermissionAction from documents.permissions import PermissionGrantees from documents.permissions import PermissionsSpec from documents.permissions import get_document_count_filter_for_user -from documents.permissions import get_groups_with_only_permission from documents.permissions import has_perms_owner_aware from documents.permissions import permitted_document_ids from documents.permissions import restrict_queryset_to_visible @@ -337,9 +337,9 @@ class OwnedObjectSerializer( ) else: # groups return list( - get_groups_with_only_permission( + get_groups_with_perms( obj, - codename=f"{codename}_{obj.__class__.__name__.lower()}", + only_with_perms_in=[f"{codename}_{obj.__class__.__name__.lower()}"], ).values_list("id", flat=True), ) diff --git a/src/documents/tests/test_views.py b/src/documents/tests/test_views.py index df2601120..d91ced30a 100644 --- a/src/documents/tests/test_views.py +++ b/src/documents/tests/test_views.py @@ -292,6 +292,33 @@ class TestViews(DirectoriesMixin, TestCase): else: assert False, f"Unexpected tag found: {tag['name']}" + def test_retrieve_with_full_permissions(self) -> None: + """ + GIVEN: + - A tag with view granted to two groups and change granted to only + one of them + WHEN: + - The single tag is requested with full permissions + THEN: + - Each action lists only the groups granted that action + """ + view_only = Group.objects.create(name="view_only") + view_and_change = Group.objects.create(name="view_and_change") + tag = Tag.objects.create(name="invoice") + grant_object(view_only, tag, "view_tag") + grant_object(view_and_change, tag, "view_tag", "change_tag") + grant_global(self.user, "view_tag") + + self.client.force_login(self.user) + response = self.client.get(f"/api/tags/{tag.pk}/?full_perms=true") + + assert response.status_code == 200 + permissions = response.json()["permissions"] + assert sorted(permissions["view"]["groups"]) == sorted( + [view_only.pk, view_and_change.pk], + ) + assert permissions["change"]["groups"] == [view_and_change.pk] + def test_list_no_n_plus_1_queries(self) -> None: """ GIVEN: