♻️(api) refactor getting versions to expose pagination

Getting versions was not working properly. Some versions returned
were not accessible by the user requesting the list of available
versions.

We refactor the code to make it simpler and let the frontend handle
pagination (load more style).
This commit is contained in:
Samuel Paccoud - DINUM
2024-09-16 19:27:48 +02:00
committed by Samuel Paccoud
parent 827d8cc8e1
commit a2a184bb93
6 changed files with 269 additions and 107 deletions

View File

@@ -343,10 +343,10 @@ class InvitationSerializer(serializers.ModelSerializer):
return attrs
class DocumentVersionSerializer(serializers.Serializer):
"""Serialize Versions."""
class VersionFilterSerializer(serializers.Serializer):
"""Validate version filters applied to the list endpoint."""
etag = serializers.CharField()
is_latest = serializers.BooleanField()
last_modified = serializers.DateTimeField()
version_id = serializers.CharField()
version_id = serializers.CharField(required=False, allow_blank=True)
page_size = serializers.IntegerField(
required=False, min_value=1, max_value=50, default=20
)

View File

@@ -10,6 +10,7 @@ from django.contrib.postgres.aggregates import ArrayAgg
from django.core.exceptions import ValidationError
from django.core.files.storage import default_storage
from django.db.models import (
Min,
OuterRef,
Q,
Subquery,
@@ -373,28 +374,36 @@ class DocumentViewSet(
Return the document's versions but only those created after the user got access
to the document
"""
if not request.user.is_authenticated:
user = request.user
if not user.is_authenticated:
raise exceptions.PermissionDenied("Authentication required.")
# Validate query parameters using dedicated serializer
serializer = serializers.VersionFilterSerializer(data=request.query_params)
serializer.is_valid(raise_exception=True)
document = self.get_object()
user = request.user
from_datetime = min(
access.created_at
for access in document.accesses.filter(
Q(user=user) | Q(team__in=user.teams),
# Users should not see version history dating from before they gained access to the
# document. Filter to get the minimum access date for the logged-in user
access_queryset = document.accesses.filter(
Q(user=user) | Q(team__in=user.teams)
).aggregate(min_date=Min("created_at"))
# Handle the case where the user has no accesses
min_datetime = access_queryset["min_date"]
if not min_datetime:
return exceptions.PermissionDenied(
"Only users with specific access can see version history"
)
versions_data = document.get_versions_slice(
from_version_id=serializer.validated_data.get("version_id"),
min_datetime=min_datetime,
page_size=serializer.validated_data.get("page_size"),
)
versions_data = document.get_versions_slice(from_datetime=from_datetime)[
"versions"
]
paginator = pagination.PageNumberPagination()
paginated_versions = paginator.paginate_queryset(versions_data, request)
serialized_versions = serializers.DocumentVersionSerializer(
paginated_versions, many=True
)
return paginator.get_paginated_response(serialized_versions.data)
return drf_response.Response(versions_data)
@decorators.action(
detail=True,
@@ -414,13 +423,13 @@ class DocumentViewSet(
# Don't let users access versions that were created before they were given access
# to the document
user = request.user
from_datetime = min(
min_datetime = min(
access.created_at
for access in document.accesses.filter(
Q(user=user) | Q(team__in=user.teams),
)
)
if response["LastModified"] < from_datetime:
if response["LastModified"] < min_datetime:
raise Http404
if request.method == "DELETE":