(backend) we want to display ancestors accesses on a document share

The document accesses a user have on a document's ancestors also apply
to this document. The frontend needs to list them as "inherited" so we
need to add them to the list.
Adding a "document_id" field on the output will allow the frontend to
differentiate between inherited and direct accesses on a document.
This commit is contained in:
Samuel Paccoud - DINUM
2025-04-12 13:43:30 +02:00
committed by Anthony LC
parent df2b953e53
commit fae024229e
5 changed files with 113 additions and 82 deletions

View File

@@ -97,7 +97,7 @@ class BaseAccessSerializer(serializers.ModelSerializer):
if not self.Meta.model.objects.filter( # pylint: disable=no-member
Q(user=user) | Q(team__in=user.teams),
role__in=[models.RoleChoices.OWNER, models.RoleChoices.ADMIN],
role__in=models.PRIVILEGED_ROLES,
**{self.Meta.resource_field_name: resource_id}, # pylint: disable=no-member
).exists():
raise exceptions.PermissionDenied(
@@ -124,6 +124,10 @@ class BaseAccessSerializer(serializers.ModelSerializer):
class DocumentAccessSerializer(BaseAccessSerializer):
"""Serialize document accesses."""
document_id = serializers.PrimaryKeyRelatedField(
read_only=True,
source="document",
)
user_id = serializers.PrimaryKeyRelatedField(
queryset=models.User.objects.all(),
write_only=True,
@@ -136,11 +140,11 @@ class DocumentAccessSerializer(BaseAccessSerializer):
class Meta:
model = models.DocumentAccess
resource_field_name = "document"
fields = ["id", "user", "user_id", "team", "role", "abilities"]
read_only_fields = ["id", "abilities"]
fields = ["id", "document_id", "user", "user_id", "team", "role", "abilities"]
read_only_fields = ["id", "document_id", "abilities"]
class DocumentAccessLightSerializer(DocumentAccessSerializer):
class DocumentAccessLightSerializer(BaseAccessSerializer):
"""Serialize document accesses with limited fields."""
user = UserLightSerializer(read_only=True)

View File

@@ -8,7 +8,6 @@ from urllib.parse import unquote, urlencode, urlparse
from django.conf import settings
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.search import TrigramSimilarity
from django.core.cache import cache
from django.core.exceptions import ValidationError
@@ -1511,12 +1510,10 @@ class DocumentAccessViewSet(
queryset = models.DocumentAccess.objects.select_related("user").all()
resource_field_name = "document"
serializer_class = serializers.DocumentAccessSerializer
is_current_user_owner_or_admin = False
def list(self, request, *args, **kwargs):
"""Return accesses for the current document with filters and annotations."""
user = self.request.user
queryset = self.filter_queryset(self.get_queryset())
try:
document = models.Document.objects.get(pk=self.kwargs["resource_id"])
@@ -1527,22 +1524,35 @@ class DocumentAccessViewSet(
if not roles:
return drf.response.Response([])
is_owner_or_admin = bool(roles.intersection(set(models.PRIVILEGED_ROLES)))
self.is_current_user_owner_or_admin = is_owner_or_admin
if not is_owner_or_admin:
ancestors = (
(document.get_ancestors() | models.Document.objects.filter(pk=document.pk))
.filter(ancestors_deleted_at__isnull=True)
.order_by("path")
)
highest_readable = ancestors.readable_per_se(user).only("depth").first()
if highest_readable is None:
return drf.response.Response([])
queryset = self.get_queryset()
queryset = queryset.filter(
document__in=ancestors.filter(depth__gte=highest_readable.depth)
)
is_privileged = bool(roles.intersection(set(models.PRIVILEGED_ROLES)))
if is_privileged:
serializer_class = serializers.DocumentAccessSerializer
else:
# Return only the document's privileged accesses
queryset = queryset.filter(role__in=models.PRIVILEGED_ROLES)
serializer_class = serializers.DocumentAccessLightSerializer
queryset = queryset.distinct()
serializer = self.get_serializer(queryset, many=True)
serializer = serializer_class(
queryset, many=True, context=self.get_serializer_context()
)
return drf.response.Response(serializer.data)
def get_serializer_class(self):
if self.action == "list" and not self.is_current_user_owner_or_admin:
return serializers.DocumentAccessLightSerializer
return super().get_serializer_class()
def perform_create(self, serializer):
"""Add a new access to the document and send an email to the new added user."""
access = serializer.save()