From 774c2ce2482095894c77a1af2843198943677d62 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 | 6 ++++++ .../core/tests/documents/test_api_documents_list.py | 9 +++++---- .../core/tests/documents/test_api_documents_retrieve.py | 6 ++++++ .../core/tests/documents/test_api_documents_update.py | 4 ++-- 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea46e8e1..46e174b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,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 - 🌐(backend) add German translation #259 - 🌐(frontend) add German translation #255 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 dfe41be6..3cca5263 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -1,4 +1,5 @@ """API endpoints""" +# pylint: disable=too-many-lines import re import uuid @@ -10,6 +11,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, @@ -334,6 +336,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", distinct=True)) + if not user.is_authenticated: # If the user is not authenticated, annotate `is_favorite` as False return queryset.annotate(is_favorite=Value(False)) @@ -360,6 +365,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..d185f4e7 100644 --- a/src/backend/core/tests/documents/test_api_documents_list.py +++ b/src/backend/core/tests/documents/test_api_documents_list.py @@ -39,9 +39,11 @@ def test_api_documents_list_format(): client = APIClient() client.force_login(user) + other_users = factories.UserFactory.create_batch(3) document = factories.DocumentFactory( users=[user, *factories.UserFactory.create_batch(2)], - favorited_by=[user, *factories.UserFactory.create_batch(2)], + favorited_by=[user, *other_users], + link_traces=other_users, ) response = client.get("/api/v1.0/documents/") @@ -63,6 +65,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 +95,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]