From 644c37651eb6444c775b2a955c6f25a06f541fd4 Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Sat, 9 Nov 2024 18:33:48 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(backend)=20annotate=20number=20of=20a?= =?UTF-8?q?ccesses=20on=20documents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new UI will display the number of accesses on each document. /!\ Once team accesses will be used, this will not represent the number of people with access anymore and will have to be improved by computing the number of people in each team. --- CHANGELOG.md | 1 + src/backend/core/api/serializers.py | 5 +++++ src/backend/core/api/viewsets.py | 5 +++++ src/backend/core/tests/documents/test_api_documents_list.py | 5 ++--- .../core/tests/documents/test_api_documents_retrieve.py | 6 ++++++ .../core/tests/documents/test_api_documents_update.py | 4 ++-- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6eb2bb8..b396a90c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to ## Added +- ✨(backend) annotate number of accesses on documents in list view #411 - ✨(backend) allow users to mark/unmark documents as favorite #411 - 🌐(frontend) Add German translation #255 - ✨(frontend) Add a broadcast store #387 diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py index 9298ae5a..589346b7 100644 --- a/src/backend/core/api/serializers.py +++ b/src/backend/core/api/serializers.py @@ -141,6 +141,7 @@ class ListDocumentSerializer(BaseResourceSerializer): """Serialize documents with limited fields for display in lists.""" is_favorite = serializers.BooleanField(read_only=True) + nb_accesses = serializers.IntegerField(read_only=True) class Meta: model = models.Document @@ -152,6 +153,7 @@ class ListDocumentSerializer(BaseResourceSerializer): "is_favorite", "link_role", "link_reach", + "nb_accesses", "title", "updated_at", ] @@ -162,6 +164,7 @@ class ListDocumentSerializer(BaseResourceSerializer): "is_favorite", "link_role", "link_reach", + "nb_accesses", "updated_at", ] @@ -181,6 +184,7 @@ class DocumentSerializer(ListDocumentSerializer): "is_favorite", "link_role", "link_reach", + "nb_accesses", "title", "updated_at", ] @@ -191,6 +195,7 @@ class DocumentSerializer(ListDocumentSerializer): "is_avorite", "link_role", "link_reach", + "nb_accesses", "updated_at", ] diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 09f9b08b..ec1b5630 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -10,6 +10,7 @@ from django.contrib.postgres.search import TrigramSimilarity from django.core.exceptions import ValidationError from django.core.files.storage import default_storage from django.db.models import ( + Count, Exists, Min, OuterRef, @@ -332,6 +333,9 @@ class DocumentViewSet( queryset = super().get_queryset() user = self.request.user + # Annotate the number of accesses associated with each document + queryset = queryset.annotate(nb_accesses=Count("accesses")) + if not user.is_authenticated: # If the user is not authenticated, annotate `is_favorite` as False return queryset.annotate(is_favorite=Value(False)) @@ -358,6 +362,7 @@ class DocumentViewSet( """Restrict resources returned by the list endpoint""" queryset = self.filter_queryset(self.get_queryset()) user = self.request.user + if user.is_authenticated: queryset = queryset.filter( Q(accesses__user=user) diff --git a/src/backend/core/tests/documents/test_api_documents_list.py b/src/backend/core/tests/documents/test_api_documents_list.py index 9e71ef0a..271033f3 100644 --- a/src/backend/core/tests/documents/test_api_documents_list.py +++ b/src/backend/core/tests/documents/test_api_documents_list.py @@ -63,6 +63,7 @@ def test_api_documents_list_format(): "is_favorite": True, "link_reach": document.link_reach, "link_role": document.link_role, + "nb_accesses": 3, "title": document.title, "updated_at": document.updated_at.isoformat().replace("+00:00", "Z"), } @@ -92,9 +93,7 @@ def test_api_documents_list_authenticated_direct(django_assert_num_queries): expected_ids = {str(document.id) for document in documents} with django_assert_num_queries(3): - response = client.get( - "/api/v1.0/documents/", - ) + response = client.get("/api/v1.0/documents/") assert response.status_code == 200 results = response.json()["results"] diff --git a/src/backend/core/tests/documents/test_api_documents_retrieve.py b/src/backend/core/tests/documents/test_api_documents_retrieve.py index adad3780..2fd253ac 100644 --- a/src/backend/core/tests/documents/test_api_documents_retrieve.py +++ b/src/backend/core/tests/documents/test_api_documents_retrieve.py @@ -38,6 +38,7 @@ def test_api_documents_retrieve_anonymous_public(): "versions_list": False, "versions_retrieve": False, }, + "nb_accesses": 0, "content": document.content, "created_at": document.created_at.isoformat().replace("+00:00", "Z"), "is_favorite": False, @@ -102,6 +103,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated( "is_favorite": False, "link_reach": reach, "link_role": document.link_role, + "nb_accesses": 0, "title": document.title, "updated_at": document.updated_at.isoformat().replace("+00:00", "Z"), } @@ -188,6 +190,7 @@ def test_api_documents_retrieve_authenticated_related_direct(): "is_favorite": False, "link_reach": document.link_reach, "link_role": document.link_role, + "nb_accesses": 2, "title": document.title, "updated_at": document.updated_at.isoformat().replace("+00:00", "Z"), } @@ -272,6 +275,7 @@ def test_api_documents_retrieve_authenticated_related_team_members( assert response.json() == { "id": str(document.id), "abilities": document.get_abilities(user), + "nb_accesses": 5, "content": document.content, "created_at": document.created_at.isoformat().replace("+00:00", "Z"), "is_favorite": False, @@ -326,6 +330,7 @@ def test_api_documents_retrieve_authenticated_related_team_administrators( assert response.json() == { "id": str(document.id), "abilities": document.get_abilities(user), + "nb_accesses": 5, "content": document.content, "created_at": document.created_at.isoformat().replace("+00:00", "Z"), "is_favorite": False, @@ -381,6 +386,7 @@ def test_api_documents_retrieve_authenticated_related_team_owners( assert response.json() == { "id": str(document.id), "abilities": document.get_abilities(user), + "nb_accesses": 5, "content": document.content, "created_at": document.created_at.isoformat().replace("+00:00", "Z"), "is_favorite": False, diff --git a/src/backend/core/tests/documents/test_api_documents_update.py b/src/backend/core/tests/documents/test_api_documents_update.py index e333e49d..f37907be 100644 --- a/src/backend/core/tests/documents/test_api_documents_update.py +++ b/src/backend/core/tests/documents/test_api_documents_update.py @@ -216,7 +216,7 @@ def test_api_documents_update_authenticated_editor_administrator_or_owner( document = models.Document.objects.get(pk=document.pk) document_values = serializers.DocumentSerializer(instance=document).data for key, value in document_values.items(): - if key in ["id", "created_at", "link_reach", "link_role"]: + if key in ["id", "created_at", "link_reach", "link_role", "nb_accesses"]: assert value == old_document_values[key] elif key == "updated_at": assert value > old_document_values[key] @@ -255,7 +255,7 @@ def test_api_documents_update_authenticated_owners(via, mock_user_teams): document = models.Document.objects.get(pk=document.pk) document_values = serializers.DocumentSerializer(instance=document).data for key, value in document_values.items(): - if key in ["id", "created_at", "link_reach", "link_role"]: + if key in ["id", "created_at", "link_reach", "link_role", "nb_accesses"]: assert value == old_document_values[key] elif key == "updated_at": assert value > old_document_values[key]